OLT Initialization state machine

This statemachine takes a disconnected OLT to an init
state. It follows the scapy automata design pattern.
It allows for state transitions to be actuated from
a command or the reception of a packet.

Change-Id: I8dc78c977099b67f76795dcb6ea2eeb458dd55a6
diff --git a/voltha/adapters/microsemi/OltStateMachine.py b/voltha/adapters/microsemi/OltStateMachine.py
new file mode 100644
index 0000000..a2db517
--- /dev/null
+++ b/voltha/adapters/microsemi/OltStateMachine.py
@@ -0,0 +1,387 @@
+#
+# Copyright 2016 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.
+#
+from scapy.automaton import ATMT, Automaton
+from scapy.layers.l2 import sendp
+import structlog
+from voltha.adapters.microsemi.PAS5211 import PAS5211MsgGetProtocolVersion, PAS5211MsgGetOltVersion, \
+    PAS5211MsgGetOltVersionResponse, PAS5211MsgGetProtocolVersionResponse, PAS5211MsgSetOltOptics, BurstTimingCtrl, \
+    SnrBurstDelay, RngBurstDelay, GeneralOpticsParams, ResetValues, ResetTimingCtrl, PreambleParams, \
+    PAS5211MsgSetOltOpticsResponse, CHANNELS, PON_OPTICS_VOLTAGE_IF_LVPECL, PON_ENABLE, PON_POLARITY_ACTIVE_HIGH, \
+    PON_SD_SOURCE_LASER_SD, PON_RESET_TYPE_DELAY_BASED, PON_DISABLE, PON_RESET_TYPE_NORMAL_START_BURST_BASED, \
+    PAS5211MsgSetOpticsIoControl, PON_POLARITY_ACTIVE_LOW, PAS5211MsgSetOpticsIoControlResponse, \
+    PAS5211MsgGetGeneralParam, PON_TX_ENABLE_DEFAULT, PAS5211MsgGetGeneralParamResponse, PAS5211MsgAddOltChannel, \
+    PAS5211MsgAddOltChannelResponse, PON_ALARM_LOS, PAS5211MsgSetAlarmConfigResponse
+from voltha.adapters.microsemi.PAS5211_utils import general_param, olt_optics_pkt, burst_timing, io_ctrl_optics, \
+    alarm_config
+
+log = structlog.get_logger()
+_verbose = False
+
+
+
+class OltStateMachine(Automaton):
+
+    comm = None
+    retry = 3
+    iface = None
+    target = None
+    verbose = None
+
+    send_state = []
+
+    def parse_args(self, debug=0, store=0, **kwargs):
+        self.comm = kwargs.pop('comm', None)
+        self.target = kwargs.pop('target', None)
+        Automaton.parse_args(self, debug=debug, store=store, **kwargs)
+        self.verbose = kwargs.get('verbose', _verbose)
+        self.iface = kwargs.get('iface', "eth0")
+
+        if self.comm is None or self.target is None:
+            raise ValueError("Missing comm or target")
+
+    def my_send(self, pkt):
+        sendp(pkt, iface=self.iface, verbose=self.verbose)
+
+    def master_filter(self, pkt):
+        """
+        Anything coming from the OLT is for us
+        :param pkt: incoming packet
+        :return: True if it came from the olt
+        """
+        return pkt.src == self.target
+
+    def debug(self, lvl, msg):
+        if self.debug_level >= lvl:
+            log.info(msg)
+
+    def p(self, pkt, channel_id=-1):
+        return self.comm.frame(pkt, channel_id=channel_id)
+
+    def check_channel_state(self):
+        for i in CHANNELS:
+                if not self.send_state[i]:
+                    return False
+        self.send_state = []
+        return True
+
+    @ATMT.state(initial=1)
+    def disconnected(self):
+        pass
+
+    @ATMT.state()
+    def wait_for_proto_version(self):
+        pass
+
+    @ATMT.state()
+    def got_proto_version(self):
+        pass
+
+    @ATMT.state()
+    def wait_for_olt_version(self):
+        pass
+
+    @ATMT.state()
+    def got_olt_version(self):
+        pass
+
+    @ATMT.state()
+    def wait_olt_optics(self):
+        pass
+
+    @ATMT.state()
+    def got_olt_optics(self):
+        pass
+
+    @ATMT.state()
+    def wait_olt_io_optics(self):
+        pass
+
+    @ATMT.state()
+    def got_olt_io_optics(self):
+        pass
+
+    @ATMT.state()
+    def wait_query_response(self):
+        pass
+
+    @ATMT.state()
+    def got_query_response(self):
+        pass
+
+    @ATMT.state()
+    def wait_olt_add(self):
+        pass
+
+    @ATMT.state()
+    def got_olt_add(self):
+        pass
+
+    @ATMT.state()
+    def wait_alarm_set(self):
+        pass
+
+    @ATMT.state()
+    def got_alarm_set(self):
+        pass
+
+    @ATMT.state(final=1)
+    def initialized(self):
+        pass
+
+    @ATMT.state(error=1)
+    def ERROR(self):
+        pass
+
+
+
+    #Transitions from disconnected state
+    @ATMT.condition(disconnected)
+    def send_proto_request(self):
+        self.send(self.p(PAS5211MsgGetProtocolVersion()))
+        raise self.wait_for_proto_version()
+
+    #Transitions from wait_for_proto_version
+    @ATMT.timeout(wait_for_proto_version, 1)
+    def timeout_proto(self):
+        log.info("Timed out waiting for proto version")
+        self.retry -= 1
+        if self.retry < 0:
+            log.debug("Too many retries, aborting.")
+            raise self.ERROR()
+        raise self.disconnected()
+
+    @ATMT.receive_condition(wait_for_proto_version)
+    def receive_proto_version(self, pkt):
+        log.debug("Received proto version {}".format(type(pkt)))
+        if PAS5211MsgGetProtocolVersionResponse in pkt:
+            raise self.got_proto_version()
+        else:
+            log.error("Got garbage packet {}".format(pkt))
+            raise self.ERROR()
+
+    # Transitions from got_proto_version
+    @ATMT.condition(got_proto_version)
+    def send_olt_version(self):
+        self.send(self.p(PAS5211MsgGetOltVersion()))
+        raise self.wait_for_olt_version()
+
+    # Transitions from waiting for olt version
+    @ATMT.timeout(wait_for_olt_version, 1)
+    def timeout_olt(self):
+        log.debug("Timed out waiting for olt version")
+        self.retry -= 1
+        if self.retry < 0:
+            log.debug("Too many retries, aborting.")
+            raise self.ERROR()
+        raise self.disconnected()
+
+    @ATMT.receive_condition(wait_for_olt_version)
+    def receive_olt_version(self, pkt):
+        log.debug("Received proto version {}".format(pkt))
+        if PAS5211MsgGetOltVersionResponse in pkt:
+            raise self.got_olt_version()
+        else:
+            log.error("Got garbage packet {}".format(pkt))
+            raise self.ERROR()
+
+    # Transitions from got_olt_version
+    @ATMT.condition(got_olt_version)
+    def send_olt_optics(self):
+        snr_burst_delay = SnrBurstDelay(timer_delay=8, preamble_delay=32,
+                                        delimiter_delay=128, burst_delay=128)
+        rng_burst_delay = RngBurstDelay(timer_delay=8, preamble_delay=32,
+                                        delimiter_delay=128)
+
+        general_optics_param = GeneralOpticsParams(laser_reset_polarity=PON_POLARITY_ACTIVE_HIGH,
+                                                   laser_sd_polarity=PON_POLARITY_ACTIVE_HIGH,
+                                                   sd_source=PON_SD_SOURCE_LASER_SD, sd_hold_snr_ranging=PON_DISABLE,
+                                                   sd_hold_normal=PON_DISABLE, reset_type_snr_ranging=PON_RESET_TYPE_DELAY_BASED,
+                                                   reset_type_normal=PON_RESET_TYPE_NORMAL_START_BURST_BASED,
+                                                   laser_reset_enable=PON_ENABLE)
+
+        reset = ResetTimingCtrl(reset_data_burst=ResetValues(bcdr_reset_d2=1,
+                                                             bcdr_reset_d1=11,
+                                                             laser_reset_d2=2,
+                                                             laser_reset_d1=5),
+                                reset_snr_burst=ResetValues(bcdr_reset_d2=2,
+                                                             bcdr_reset_d1=9,
+                                                             laser_reset_d2=2,
+                                                             laser_reset_d1=1),
+                                reset_rng_burst=ResetValues(bcdr_reset_d2=2,
+                                                             bcdr_reset_d1=9,
+                                                             laser_reset_d2=2,
+                                                             laser_reset_d1=1),
+                                single_reset=ResetValues(bcdr_reset_d2=1,
+                                                             bcdr_reset_d1=1,
+                                                             laser_reset_d2=1,
+                                                             laser_reset_d1=1),
+                                double_reset=ResetValues(bcdr_reset_d2=1,
+                                                             bcdr_reset_d1=1,
+                                                             laser_reset_d2=1,
+                                                             laser_reset_d1=1))
+
+        preamble = PreambleParams(correlation_preamble_length=8, preamble_length_snr_rng=119,
+                                  guard_time_data_mode=32, type1_size_data=0,
+                                  type2_size_data=0, type3_size_data=5,
+                                  type3_pattern=170, delimiter_size=20,
+                                  delimiter_byte1=171, delimiter_byte2=89,
+                                  delimiter_byte3=131)
+
+        olt_optics = olt_optics_pkt(PON_OPTICS_VOLTAGE_IF_LVPECL, burst=burst_timing(1, 1,
+                                                    snr_burst=snr_burst_delay,
+                                                    rng_burst=rng_burst_delay),
+                                 general=general_optics_param,
+                                 reset=reset,
+                                 preamble=preamble)
+
+        for id in CHANNELS:
+            self.send_state.append(False)
+            self.send(self.p(olt_optics, channel_id=id))
+
+        raise self.wait_olt_optics()
+
+    #Transitions from wait_olt_optics
+    @ATMT.timeout(wait_olt_optics, 3)
+    def olt_optics_timeout(self):
+        log.error("Setting olt optics failed; disconnecting")
+        raise self.ERROR()
+
+    @ATMT.receive_condition(wait_olt_optics)
+    def receive_set_optics_response(self, pkt):
+        if pkt.opcode == PAS5211MsgSetOltOpticsResponse.opcode:
+            self.send_state[pkt.channel_id] = True
+            if self.check_channel_state():
+                raise self.got_olt_optics()
+            raise self.wait_olt_optics()
+
+    #Transitions from got_olt_optics
+    @ATMT.condition(got_olt_optics)
+    def send_olt_io_optics(self):
+
+        pkt = io_ctrl_optics(1, 0, 6, 14)
+        self.send_state.append(False)
+        self.send(self.p(pkt, channel_id=0))
+
+        pkt = io_ctrl_optics(3, 2, 7, 15)
+        self.send_state.append(False)
+        self.send(self.p(pkt, channel_id=1))
+
+        pkt = io_ctrl_optics(11, 10, 8, 16)
+        self.send_state.append(False)
+        self.send(self.p(pkt, channel_id=2))
+
+        pkt = io_ctrl_optics(13, 12, 9, 17)
+        self.send_state.append(False)
+        self.send(self.p(pkt, channel_id=3))
+
+        raise self.wait_olt_io_optics()
+
+    #Transitions from wait olt io optics
+    @ATMT.timeout(wait_olt_io_optics, 3)
+    def olt_io_optics_timeout(self):
+        log.error("Setting olt io optics failed; disconnecting")
+        raise self.ERROR()
+
+    @ATMT.receive_condition(wait_olt_io_optics)
+    def receive_io_optics_response(self, pkt):
+        if pkt.opcode == PAS5211MsgSetOpticsIoControlResponse.opcode:
+            self.send_state[pkt.channel_id] = True
+            if self.check_channel_state():
+                raise self.got_olt_io_optics()
+            raise self.wait_olt_io_optics()
+
+    # Transitions got olt io optics
+    @ATMT.condition(got_olt_io_optics)
+    def check_downstream_pon_tx(self):
+        query = general_param(PON_TX_ENABLE_DEFAULT)
+        for id in CHANNELS:
+            self.send_state.append(False)
+            self.send(self.p(query, channel_id=id))
+
+        raise self.wait_query_response()
+
+    # Transitions from wait query response
+    @ATMT.timeout(wait_query_response, 3)
+    def query_timeout(self):
+        log.error("Our queries have gone unanswered; disconnecting")
+        raise self.ERROR()
+
+    @ATMT.receive_condition(wait_query_response)
+    def check_pon_tx_state(self, pkt):
+        if PAS5211MsgGetGeneralParamResponse in pkt:
+            self.send_state[pkt.channel_id] = True
+            if pkt.value == PON_ENABLE:
+                # we may want to do something here.
+                if self.check_channel_state():
+                    raise self.got_query_response()
+                else:
+                    raise self.wait_query_response()
+            else:
+                log.error("TX downstream is not enabled")
+                raise self.ERROR()
+
+    # Transitions from got_query_response
+    @ATMT.condition(wait_query_response)
+    def send_add_olt(self):
+        olt_add = PAS5211MsgAddOltChannel()
+        for id in CHANNELS:
+            self.send_state.append(False)
+            self.send(self.p(olt_add, channel_id=id))
+        raise self.wait_olt_add()
+
+    # Transitions from wait_olt_add
+    @ATMT.timeout(wait_olt_add, 3)
+    def olt_add_timeout(self):
+        log.error("Cannot add olts; disconnecting")
+        raise self.ERROR()
+
+    @ATMT.receive_condition(wait_olt_add)
+    def wait_for_olt_add(self, pkt):
+        if pkt.opcode == PAS5211MsgAddOltChannelResponse.opcode:
+            self.send_state[pkt.channel_id] = True
+            if self.check_channel_state():
+                raise self.got_olt_add()
+            raise self.wait_olt_add()
+
+    # Transitions from got_olt_add
+    @ATMT.condition(got_olt_add)
+    def send_alarm_config(self):
+        alarm_msg = alarm_config(PON_ALARM_LOS, PON_ENABLE)
+        for id in CHANNELS:
+            self.send_state.append(False)
+            self.send(self.p(alarm_msg, channel_id=id))
+        raise self.wait_alarm_set()
+
+    # Transitions for wait_alarm_set
+    @ATMT.timeout(wait_alarm_set, 3)
+    def alarm_timeout(self):
+        log.error("Couldn't set alarms; disconnecting")
+        raise self.ERROR()
+
+    @ATMT.receive_condition(wait_alarm_set)
+    def wait_for_alarm_set(self, pkt):
+        if pkt.opcode == PAS5211MsgSetAlarmConfigResponse.opcode:
+            self.send_state[pkt.channel_id] = True
+            if self.check_channel_state():
+                raise self.got_alarm_set()
+            raise self.wait_alarm_set()
+
+    @ATMT.timeout(got_alarm_set, 1)
+    def send_keepalive(self):
+        self.send(self.p(PAS5211MsgGetOltVersion()))
+        raise self.got_alarm_set()
+
+
diff --git a/voltha/adapters/microsemi/PAS5211.py b/voltha/adapters/microsemi/PAS5211.py
index ec9e8b8..f24af17 100644
--- a/voltha/adapters/microsemi/PAS5211.py
+++ b/voltha/adapters/microsemi/PAS5211.py
@@ -18,14 +18,202 @@
 """
 PAS5211 scapy structs used for interaction with Ruby
 """
-from scapy.fields import LEShortField, Field, LEIntField, LESignedIntField, FieldLenField, FieldListField
+from scapy.fields import LEShortField, Field, LEIntField, LESignedIntField, FieldLenField, FieldListField, PacketField, \
+    ByteField
 from scapy.layers.l2 import Dot3, LLC
+from scapy.layers.inet import ARP
 from scapy.packet import Packet, bind_layers, split_layers
 from scapy.utils import lhex
 from scapy.volatile import RandSInt
 from scapy.layers.ntp import XLEShortField
 
 """
+PAS5211 Constants
+"""
+CHANNELS=range(0,4)
+
+# from enum PON_true_false_t
+PON_FALSE = 0
+PON_TRUE = 1
+
+# from enum PON_enable_disable_t
+PON_DISABLE = 0
+PON_ENABLE = 1
+
+# from enym PON_mac_t
+PON_MII = 0
+PON_GMII = 1
+PON_TBI = 2
+
+PON_POLARITY_ACTIVE_LOW = 0
+PON_POLARITY_ACTIVE_HIGH = 1
+
+PON_OPTICS_VOLTAGE_IF_UNDEFINED = 0
+PON_OPTICS_VOLTAGE_IF_CML = 1
+PON_OPTICS_VOLTAGE_IF_LVPECL = 2
+
+PON_SD_SOURCE_LASER_SD = 0
+PON_SD_SOURCE_BCDR_LOCK = 1
+PON_SD_SOURCE_BCDR_SD = 2
+
+PON_RESET_TYPE_DELAY_BASED = 0
+PON_RESET_TYPE_SINGLE_RESET = 1
+PON_RESET_TYPE_DOUBLE_RESET = 2
+
+PON_RESET_TYPE_NORMAL_START_BURST_BASED = 0
+PON_RESET_TYPE_NORMAL_END_BURST_BASED = 1
+
+#from PON_general_parameters_type_t
+PON_COMBINED_LOSI_LOFI = 1000,
+PON_TX_ENABLE_DEFAULT = 1001,
+PON_FALSE_Q_FULL_EVENT_MODE = 1002,             #Enable or disable False queue full event from DBA
+PON_PID_AID_MISMATCH_MIN_SILENCE_PERIOD = 1003, #Set PID_AID_MISMATCH min silence period. 0 - disable, Else - period in secs
+PON_ENABLE_CLEAR_ALARM          = 1004,         #Set if FW generate clear alarm. 0 - generate clear alarm, Else - don't generate clear alarm
+PON_ASSIGN_ALLOC_ID_PLOAM       = 1005,         #Enable or disabl send assign alloc id ploam. 0 - disable, 1 - enable
+PON_BIP_ERR_POLLING_PERIOD_MS   = 1006,         #BIP error polling period, 200 - 65000, 0 - Disabled, Recommended: 5000 (default)
+PON_IGNORE_SN_WHEN_ACTIVE		= 1007,         #Ignore SN when decatived 0 - consider SN (deactivate the onu if received same SN when activated (default)	1 - Ignore
+PON_ONU_PRE_ASSIGNED_DELAY		= 1008,		    #0xffffffff - Disabled (default). Any other value (0 - 0xfffe) indicates that PA delay is enabled, with the specified delay value and included in the US_OVERHEAD PLOAM.
+PON_DS_FRAGMENTATION			= 1009,		    #Enable or disable DS fragmentation, 0 disable, 1 enable
+PON_REI_ERRORS_REPORT_ALL		= 1010,		    #Set if fw report rei alarm when errors is 0, 0 disable (default), 1 enable
+PON_IGNORE_SFI_DEACTIVATION		= 1011,		    #Set if igonre sfi deactivation, 0 disable (default), 1 enable
+PON_OVERRIDE_ALLOCATION_OVERHEAD	= 1012,	   	#Allows to override the allocation overhead set by optic-params configuration. This configuration is only allowed when the the pon channel is disabled.
+PON_OPTICS_TIMELINE_OFFSET	= 1013,		        #Optics timeline offset, -128-127, : this parameter is very sensitive and requires coordination with PMC
+PON_LAST_GENERAL_PARAMETER		= PON_OPTICS_TIMELINE_OFFSET		   #Last general meter
+
+
+
+PON_GPIO_LINE_0 = 0
+PON_GPIO_LINE_1 = 1
+PON_GPIO_LINE_2 = 2
+PON_GPIO_LINE_3 = 3
+PON_GPIO_LINE_4 = 4
+PON_GPIO_LINE_5 = 5
+PON_GPIO_LINE_6 = 6
+PON_GPIO_LINE_7 = 7
+def PON_EXT_GPIO_LINE(line):
+    return line + 8
+
+# from enum PON_alarm_t
+PON_ALARM_SOFTWARE_ERROR = 0
+PON_ALARM_LOS = 1
+PON_ALARM_LOSI = 2
+PON_ALARM_DOWI = 3
+PON_ALARM_LOFI = 4
+PON_ALARM_RDII = 5
+PON_ALARM_LOAMI = 6
+PON_ALARM_LCDGI = 7
+PON_ALARM_LOAI = 8
+PON_ALARM_SDI = 9
+PON_ALARM_SFI = 10
+PON_ALARM_PEE = 11
+PON_ALARM_DGI = 12
+PON_ALARM_LOKI = 13
+PON_ALARM_TIWI = 14
+PON_ALARM_TIA = 15
+PON_ALARM_VIRTUAL_SCOPE_ONU_LASER_ALWAYS_ON = 16
+PON_ALARM_VIRTUAL_SCOPE_ONU_SIGNAL_DEGRADATION = 17
+PON_ALARM_VIRTUAL_SCOPE_ONU_EOL = 18
+PON_ALARM_VIRTUAL_SCOPE_ONU_EOL_DATABASE_IS_FULL = 19
+PON_ALARM_AUTH_FAILED_IN_REGISTRATION_ID_MODE = 20
+PON_ALARM_SUFI = 21
+PON_ALARM_LAST_ALARM = 22
+
+# from enum PON_general_parameters_type_t
+PON_COMBINED_LOSI_LOFI 		            = 1000
+PON_TX_ENABLE_DEFAULT 		            = 1001
+
+# Enable or disable False queue full event from DBA
+PON_FALSE_Q_FULL_EVENT_MODE             = 1002
+
+# Set PID_AID_MISMATCH min silence period. 0 - disable, Else - period in secs
+PON_PID_AID_MISMATCH_MIN_SILENCE_PERIOD = 1003
+
+# Set if FW generate clear alarm. 0 - generate clear alarm, Else - don't
+# generate clear alarm
+PON_ENABLE_CLEAR_ALARM                  = 1004
+
+# Enable or disabl send assign alloc id ploam. 0 - disable, 1 - enable
+PON_ASSIGN_ALLOC_ID_PLOAM               = 1005
+
+# BIP error polling period, 200 - 65000, 0 - Disabled, Recommended: 5000
+# (default)
+PON_BIP_ERR_POLLING_PERIOD_MS           = 1006
+
+# Ignore SN when decatived 0 - consider SN (deactivate the onu if received
+# same SN when activated (default)	1 - Ignore
+PON_IGNORE_SN_WHEN_ACTIVE		        = 1007
+
+# 0xffffffff - Disabled (default). Any other value (0 - 0xfffe) indicates
+# that PA delay is enabled, with the specified delay value and included in
+# the US_OVERHEAD PLOAM
+PON_ONU_PRE_ASSIGNED_DELAY		        = 1008
+
+# Enable or disable DS fragmentation, 0 disable, 1 enable
+PON_DS_FRAGMENTATION			        = 1009
+
+# Set if fw report rei alarm when errors is 0, 0 disable (default), 1 enable
+PON_REI_ERRORS_REPORT_ALL		        = 1010
+
+# Set if igonre sfi deactivation, 0 disable (default), 1 enable
+PON_IGNORE_SFI_DEACTIVATION		        = 1011
+
+# Allows to override the allocation overhead set by optic-params
+# configuration. This configuration is only allowed when the the pon channel
+# is disabled
+PON_OVERRIDE_ALLOCATION_OVERHEAD	    = 1012
+
+# Optics timeline offset, -128-127, : this parameter is very sensitive and
+# requires coordination with PMC
+PON_OPTICS_TIMELINE_OFFSET	            = 1013
+
+# Last general meter
+PON_LAST_GENERAL_PARAMETER		        = PON_OPTICS_TIMELINE_OFFSET
+
+# from enum PON_dba_mode_t
+PON_DBA_MODE_NOT_LOADED                 = 0
+PON_DBA_MODE_LOADED_NOT_RUNNING         = 1
+PON_DBA_MODE_RUNNING                    = 2
+PON_DBA_MODE_LAST                       = 3
+
+# from enum type typedef enum PON_port_frame_destination_t
+PON_PORT_PON = 0
+PON_PORT_SYSTEM = 1
+
+# from enum PON_olt_hw_classification_t
+
+PON_OLT_HW_CLASSIFICATION_PAUSE                    = 0
+PON_OLT_HW_CLASSIFICATION_LINK_CONSTRAINT          = 1
+PON_OLT_HW_CLASSIFICATION_IGMP                     = 2
+PON_OLT_HW_CLASSIFICATION_MPCP                     = 3
+PON_OLT_HW_CLASSIFICATION_OAM                      = 4
+PON_OLT_HW_CLASSIFICATION_802_1X                   = 5
+PON_OLT_HW_CLASSIFICATION_PPPOE_DISCOVERY          = 6
+PON_OLT_HW_CLASSIFICATION_PPPOE_SESSION            = 7
+PON_OLT_HW_CLASSIFICATION_DHCP_V4                  = 8
+PON_OLT_HW_CLASSIFICATION_PIM                      = 9
+PON_OLT_HW_CLASSIFICATION_DHCP_V6                  = 10
+PON_OLT_HW_CLASSIFICATION_ICMP_V4                  = 11
+PON_OLT_HW_CLASSIFICATION_MLD                      = 12
+PON_OLT_HW_CLASSIFICATION_ARP                      = 13
+PON_OLT_HW_CLASSIFICATION_CONF_DA                  = 14
+PON_OLT_HW_CLASSIFICATION_CONF_RULE                = 15
+PON_OLT_HW_CLASSIFICATION_DA_EQ_SA                 = 16
+PON_OLT_HW_CLASSIFICATION_DA_EQ_MAC                = 17
+PON_OLT_HW_CLASSIFICATION_DA_EQ_SEC_MAC            = 18
+PON_OLT_HW_CLASSIFICATION_SA_EQ_MAC                = 19
+PON_OLT_HW_CLASSIFICATION_SA_EQ_SEC_MAC            = 20
+PON_OLT_HW_CLASSIFICATION_ETHERNET_MANAGEMENT      = 100
+PON_OLT_HW_CLASSIFICATION_IPV4_LOCAL_MULTICAST     = 101
+PON_OLT_HW_CLASSIFICATION_IPV4_MANAGEMENT          = 102
+PON_OLT_HW_CLASSIFICATION_ALL_IPV4_MULTICAST       = 103
+PON_OLT_HW_CLASSIFICATION_IPV6_LOCAL_MULTICAST     = 104
+PON_OLT_HW_CLASSIFICATION_IPV6_MANAGEMENT          = 105
+PON_OLT_HW_CLASSIFICATION_ALL_IPV6_MULTICAST       = 106
+PON_OLT_HW_CLASSIFICATION_OTHER			           = 107
+PON_OLT_HW_CLASSIFICATION_LAST_RULE                = 108
+
+
+"""
 Extra field structs
 """
 
@@ -124,6 +312,229 @@
     def answers(self, other):
         return other.name == "PAS5211MsgGetOltVersion"
 
+
+class SnrBurstDelay(Packet):
+    name = "SnrBurstDelay"
+    fields_desc= [
+        LEShortField("timer_delay", None),
+        LEShortField("preamble_delay", None),
+        LEShortField("delimiter_delay", None),
+        LEShortField("burst_delay", None)
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+class RngBurstDelay(Packet):
+    name = "SnrBurstDelay"
+    fields_desc= [
+        LEShortField("timer_delay", None),
+        LEShortField("preamble_delay", None),
+        LEShortField("delimiter_delay", None)
+    ]
+
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class BurstTimingCtrl(Packet):
+    name = "BurstTimingCtrl"
+    fields_desc = [
+        PacketField("snr_burst_delay", None, SnrBurstDelay),
+        PacketField("rng_burst_delay", None, RngBurstDelay),
+        LEShortField("burst_delay_single", None),
+        LEShortField("burst_delay_double", None)
+
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class GeneralOpticsParams(Packet):
+    name = "GeneralOpticsParams"
+    fields_desc= [
+        ByteField("laser_reset_polarity", None),
+        ByteField("laser_sd_polarity", None),
+        ByteField("sd_source", None),
+        ByteField("sd_hold_snr_ranging", None),
+        ByteField("sd_hold_normal", None),
+        ByteField("reset_type_snr_ranging", None),
+        ByteField("reset_type_normal", None),
+        ByteField("laser_reset_enable", None),
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class ResetValues(Packet):
+    name = "ResetDataBurst"
+    fields_desc = [
+        ByteField("bcdr_reset_d2", None),
+        ByteField("bcdr_reset_d1", None),
+        ByteField("laser_reset_d2", None),
+        ByteField("laser_reset_d1", None)
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class DoubleResetValues(Packet):
+    name = "ResetDataBurst"
+    fields_desc = [
+        ByteField("bcdr_reset_d4", None),
+        ByteField("bcdr_reset_d3", None),
+        ByteField("laser_reset_d4", None),
+        ByteField("laser_reset_d3", None)
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class ResetTimingCtrl(Packet):
+    name = "ResetTimingCtrl"
+    fields_desc = [
+        PacketField("reset_data_burst", None, ResetValues),
+        PacketField("reset_snr_burst", None, ResetValues),
+        PacketField("reset_rng_burst", None, ResetValues),
+        PacketField("single_reset", None, ResetValues),
+        PacketField("double_reset", None, DoubleResetValues),
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+
+class PreambleParams(Packet):
+    name = "PreambleParams"
+    fields_desc = [
+        ByteField("correlation_preamble_length", None),
+        ByteField("preamble_length_snr_rng", None),
+        ByteField("guard_time_data_mode", None),
+        ByteField("type1_size_data", None),
+        ByteField("type2_size_data", None),
+        ByteField("type3_size_data", None),
+        ByteField("type3_pattern", None),
+        ByteField("delimiter_size", None),
+        ByteField("delimiter_byte1", None),
+        ByteField("delimiter_byte2", None),
+        ByteField("delimiter_byte3", None)
+    ]
+
+    def extract_padding(self, p):
+        return "", p
+
+class PAS5211MsgSetOltOptics(PAS5211Msg):
+
+    opcode = 106
+    name = "PAS5211MsgSetOltOptics"
+
+    fields_desc = [
+        PacketField("burst_timing_ctrl", None, BurstTimingCtrl),
+        PacketField("general_optics_params", None, GeneralOpticsParams),
+        ByteField("reserved1", 0),
+        ByteField("reserved2", 0),
+        ByteField("reserved3", 0),
+        PacketField("reset_timing_ctrl", None, ResetTimingCtrl),
+        ByteField("voltage_if_mode", None),
+        PacketField("preamble_params", None, PreambleParams),
+        ByteField("reserved4", 0),
+        ByteField("reserved5", 0),
+        ByteField("reserved6", 0)
+    ]
+
+class PAS5211MsgSetOltOpticsResponse(PAS5211Msg):
+    opcode = 10346
+    name = "PAS5211MsgSetOltOpticsResponse"
+    fields_desc = []
+
+
+class PAS5211MsgSetOpticsIoControl(PAS5211Msg):
+    opcode = 108
+    name = "PAS5211MsgSetOpticsIoControl"
+    fields_desc = [
+        ByteField("i2c_clk", None),
+        ByteField("i2c_data", None),
+        ByteField("tx_enable", None),
+        ByteField("tx_fault", None),
+        ByteField("tx_enable_polarity", None),
+        ByteField("tx_fault_polarity", None),
+    ]
+
+
+class PAS5211MsgSetOpticsIoControlResponse(PAS5211Msg):
+    opcode = 10348
+    name = "PAS5211MsgSetOpticsIoControlResponse"
+    fields_desc = [ ]
+
+
+class PAS5211MsgAddOltChannel(PAS5211Msg):
+    opcode = 4
+    name = "PAS5211MsgAddOltChannel"
+    fields_desc = [
+
+    ]
+
+
+class PAS5211MsgAddOltChannelResponse(PAS5211Msg):
+    opcode = 10244
+    name = "PAS5211MsgAddOltChannelResponse"
+    fields_desc = [
+
+    ]
+
+class PAS5211MsgGetGeneralParam(PAS5211Msg):
+    opcode = 165
+    name = "PAS5211MsgGetGeneralParam"
+    fields_desc = [
+        LEIntField("parameter", None),
+        LEIntField("reserved", 0),
+    ]
+
+
+class PAS5211MsgGetGeneralParamResponse(PAS5211Msg):
+    name = "PAS5211MsgGetGeneralParamResponse"
+    fields_desc = [
+        LEIntField("parameter", None),
+        LEIntField("reserved", 0),
+        LEIntField("value", None)
+    ]
+
+class PAS5211MsgSetAlarmConfig(PAS5211Msg):
+    opcode = 48
+    name = "PAS5211MsgSetAlarmConfig"
+    fields_desc = [
+        LEShortField("type", None),
+        LEShortField("activate", None),
+        LEIntField("parameter1", None),
+        LEIntField("parameter2", None),
+        LEIntField("parameter3", None),
+        LEIntField("parameter4", None)
+    ]
+
+
+class PAS5211MsgSetOltChannelActivationPeriod(PAS5211Msg):
+    opcode = 11
+    name = "PAS5211MsgSetOltChannelActivationPeriod"
+    fields_desc = [
+        LEIntField("activation_period", None)
+    ]
+
+
+class PAS5211MsgSetOltChannelActivationPeriodResponse(PAS5211Msg):
+    name = "PAS5211MsgSetOltChannelActivationPeriodResponse"
+    fields_desc = []
+
+
+class PAS5211MsgSetAlarmConfigResponse(PAS5211Msg):
+    opcode = 10288
+    name = "PAS5211MsgSetAlarmConfigResponse"
+    fields_desc = []
+
 """
 Bindings used for message processing
 """
@@ -132,4 +543,6 @@
 bind_layers(Dot3,PAS5211FrameHeader)
 bind_layers(PAS5211FrameHeader, PAS5211MsgHeader)
 bind_layers(PAS5211MsgHeader, PAS5211MsgGetOltVersionResponse, opcode=0x3800 | 3)
-bind_layers(PAS5211MsgHeader, PAS5211MsgGetProtocolVersionResponse, opcode=0x2800 | 2)
\ No newline at end of file
+bind_layers(PAS5211MsgHeader, PAS5211MsgGetProtocolVersionResponse, opcode=0x2800 | 2)
+bind_layers(PAS5211MsgHeader, PAS5211MsgGetGeneralParamResponse, opcode=0x2800 | 165)
+bind_layers(PAS5211MsgHeader, PAS5211MsgSetAlarmConfigResponse, opcode=0x2800 | 48)
diff --git a/voltha/adapters/microsemi/PAS5211_comm.py b/voltha/adapters/microsemi/PAS5211_comm.py
index d604077..863cfbb 100644
--- a/voltha/adapters/microsemi/PAS5211_comm.py
+++ b/voltha/adapters/microsemi/PAS5211_comm.py
@@ -58,25 +58,13 @@
 
 
 class PAS5211Communication(object):
-    def __init__(self, dst_mac, channel_id = -1, init=0, iface = None):
+    def __init__(self, dst_mac, init=0, iface = None):
         self.iface = iface
         self.dst_mac = dst_mac
         self.seqgen = sequence_generator(init)
         self.src_mac = determine_src_mac(self.iface)
-        self.channel_id = channel_id
 
-    def communicate(self, msg, timeout=1, **kwargs):
-        if self.src_mac is not None:
-            frame = constructPAS5211Frames(msg, self.seqgen.next(), self.src_mac,
-                                           self.dst_mac, channel_id=self.channel_id,
-                                           **kwargs)
-            try:
-                return srp1(frame, timeout=timeout, iface=self.iface)
-            except IOError as exc:
-                log.info('Can not communicate to ruby on mac {} because {}'
-                         .format(self.dst_mac, exc.message))
-            except select.error as exc:
-                log.info('Can not communicate to ruby on mac {} because {}'
-                         .format(self.dst_mac, exc))
-        else:
-            log.info('Unknown src mac for {}'.format(self.iface))
+    def frame(self, msg, channel_id=-1):
+        return constructPAS5211Frames(msg, self.seqgen.next(), self.src_mac,
+                                           self.dst_mac, channel_id=channel_id)
+
diff --git a/voltha/adapters/microsemi/PAS5211_hardware.py b/voltha/adapters/microsemi/PAS5211_hardware.py
new file mode 100644
index 0000000..c3a5f46
--- /dev/null
+++ b/voltha/adapters/microsemi/PAS5211_hardware.py
@@ -0,0 +1,33 @@
+#
+# Copyright 2016 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.
+#
+
+
+PON_ALARM_CODE_LOS = 0
+PON_ALARM_CODE_LOSI = 1
+PON_ALARM_CODE_DOWI = 2
+PON_ALARM_CODE_LOFI = 3
+PON_ALARM_CODE_RDII = 4
+PON_ALARM_CODE_LOAMI = 5
+PON_ALARM_CODE_LCDGI = 6
+PON_ALARM_CODE_LOAI = 7
+PON_ALARM_CODE_SDI = 8
+PON_ALARM_CODE_SFI = 9
+PON_ALARM_CODE_PEE = 10
+PON_ALARM_CODE_DGI = 11
+PON_ALARM_CODE_LOKI = 12
+PON_ALARM_CODE_TIWI = 13
+PON_ALARM_CODE_TIA = 14
+PON_ALARM_CODE_LAST_ALARM = 15
\ No newline at end of file
diff --git a/voltha/adapters/microsemi/PAS5211_utils.py b/voltha/adapters/microsemi/PAS5211_utils.py
new file mode 100644
index 0000000..e923a8c
--- /dev/null
+++ b/voltha/adapters/microsemi/PAS5211_utils.py
@@ -0,0 +1,91 @@
+#
+# Copyright 2016 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.
+#
+
+from voltha.adapters.microsemi.PAS5211 import PAS5211MsgGetGeneralParam, PON_POLARITY_ACTIVE_LOW, \
+    PON_POLARITY_ACTIVE_HIGH, PAS5211MsgSetOpticsIoControl, BurstTimingCtrl, PAS5211MsgSetOltOptics, PON_ALARM_LOS, \
+    PON_ALARM_LOSI, PON_ALARM_DOWI, PON_ALARM_LOFI, PON_ALARM_RDII, PON_ALARM_LOAMI, PON_ALARM_LCDGI, PON_ALARM_LOAI, \
+    PON_ALARM_SDI, PON_ALARM_SFI, PON_ALARM_PEE, PON_ALARM_DGI, PON_ALARM_LOKI, PON_ALARM_TIWI, PON_ALARM_TIA, \
+    PAS5211MsgSetAlarmConfig
+from voltha.adapters.microsemi.PAS5211_hardware import PON_ALARM_CODE_LOS, PON_ALARM_CODE_LOSI, PON_ALARM_CODE_DOWI, \
+    PON_ALARM_CODE_LOFI, PON_ALARM_CODE_RDII, PON_ALARM_CODE_LOAMI, PON_ALARM_CODE_LCDGI, PON_ALARM_CODE_LOAI, \
+    PON_ALARM_CODE_SDI, PON_ALARM_CODE_SFI, PON_ALARM_CODE_PEE, PON_ALARM_CODE_DGI, PON_ALARM_CODE_LOKI, \
+    PON_ALARM_CODE_TIWI, PON_ALARM_CODE_TIA, PON_ALARM_CODE_LAST_ALARM
+
+
+def general_param(parameter):
+    return PAS5211MsgGetGeneralParam(parameter=parameter)
+
+
+def io_ctrl_optics(i2c_clk, i2c_data, tx_enable, tx_fault,
+                   tx_enable_polarity = PON_POLARITY_ACTIVE_LOW,
+                   tx_fault_polarity= PON_POLARITY_ACTIVE_HIGH):
+    channel_optic_ctrl_if = PAS5211MsgSetOpticsIoControl()
+
+    channel_optic_ctrl_if.i2c_clk = i2c_clk
+    channel_optic_ctrl_if.i2c_data = i2c_data
+    channel_optic_ctrl_if.tx_enable = tx_enable
+    channel_optic_ctrl_if.tx_fault = tx_fault
+    channel_optic_ctrl_if.tx_enable_polarity = tx_enable_polarity
+    channel_optic_ctrl_if.tx_fault_polarity = tx_fault_polarity
+
+    return channel_optic_ctrl_if
+
+
+def burst_timing(single, double, snr_burst=None, rng_burst=None):
+    return BurstTimingCtrl(snr_burst_delay=snr_burst, rng_burst_delay=rng_burst,
+                           burst_delay_single=single, burst_delay_double=double)
+
+
+def olt_optics_pkt(voltage, burst=None, general=None, reset=None, preamble=None):
+    return PAS5211MsgSetOltOptics(burst_timing_ctrl=burst,
+                                  general_optics_params=general,
+                                  voltage_if_mode=voltage,
+                                  reset_timing_ctrl=reset,
+                                  preamble_params=preamble)
+
+def alarm_config(type, activate, parameters=[None, None, None, None]):
+    while len(parameters) != 4:
+        parameters.append(None)
+    return PAS5211MsgSetAlarmConfig(type=get_alarm_code_for_type(type),
+                                    activate=activate,
+                                    parameter1=parameters[0],
+                                    parameter2=parameters[1],
+                                    parameter3=parameters[2],
+                                    parameter4=parameters[3])
+
+
+def get_alarm_code_for_type(type):
+    try:
+        return {
+            PON_ALARM_LOS : PON_ALARM_CODE_LOS,
+            PON_ALARM_LOSI : PON_ALARM_CODE_LOSI,
+            PON_ALARM_DOWI : PON_ALARM_CODE_DOWI,
+            PON_ALARM_LOFI : PON_ALARM_CODE_LOFI,
+            PON_ALARM_RDII : PON_ALARM_CODE_RDII,
+            PON_ALARM_LOAMI: PON_ALARM_CODE_LOAMI,
+            PON_ALARM_LCDGI: PON_ALARM_CODE_LCDGI,
+            PON_ALARM_LOAI : PON_ALARM_CODE_LOAI,
+            PON_ALARM_SDI  : PON_ALARM_CODE_SDI,
+            PON_ALARM_SFI  : PON_ALARM_CODE_SFI,
+            PON_ALARM_PEE  : PON_ALARM_CODE_PEE,
+            PON_ALARM_DGI  : PON_ALARM_CODE_DGI,
+            PON_ALARM_LOKI : PON_ALARM_CODE_LOKI,
+            PON_ALARM_TIWI : PON_ALARM_CODE_TIWI,
+            PON_ALARM_TIA  : PON_ALARM_CODE_TIA
+        }[type]
+    except KeyError, e:
+        return PON_ALARM_CODE_LAST_ALARM
+
diff --git a/voltha/adapters/microsemi/RubyAdapter.py b/voltha/adapters/microsemi/RubyAdapter.py
index 086bd33..0d57a65 100644
--- a/voltha/adapters/microsemi/RubyAdapter.py
+++ b/voltha/adapters/microsemi/RubyAdapter.py
@@ -20,13 +20,10 @@
 import structlog
 from twisted.internet import reactor
 from voltha.adapters.interface import IAdapterInterface
-from voltha.adapters.microsemi.PAS5211 import PAS5211MsgGetOltVersion, PAS5211MsgGetOltVersionResponse
+from voltha.adapters.microsemi.OltStateMachine import OltStateMachine
 from voltha.adapters.microsemi.PAS5211_comm import PAS5211Communication
-from voltha.adapters.microsemi.StateMachine import Disconnected, States
 
 from voltha.protos import third_party
-from voltha.protos.adapter_pb2 import Adapter, AdapterConfig, DeviceTypes
-from voltha.protos.health_pb2 import HealthStatus
 
 
 from zope.interface import implementer
@@ -45,7 +42,10 @@
         self.descriptor = None
         self.comm = comm = PAS5211Communication(dst_mac=olt_conf['olts']['mac'],
                                                 iface=olt_conf['iface'])
-        self.olt = Disconnected(comm)
+        self.olt = OltStateMachine(iface=olt_conf['iface'],
+                                   comm=comm,
+                                   target=olt_conf['olts']['mac'])
+
 
     def start(self):
         log.info('starting')
@@ -55,7 +55,7 @@
 
     def stop(self):
         log.debug('stopping')
-        self.olt.disconnect()
+        self.olt.stop()
         log.info('stopped')
         return self
 
@@ -65,12 +65,14 @@
         return self.descriptor
 
     def device_types(self):
-        return DeviceTypes(
-            items=[]  # TODO
-        )
+        pass
+        #return DeviceTypes(
+        #    items=[]  # TODO
+        #)
 
     def health(self):
-        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
+        pass
+        #return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
 
     def change_master_state(self, master):
         raise NotImplementedError()
@@ -89,28 +91,8 @@
     ##
 
     def __init_olt(self):
-        olt = self.olt
-        while not olt.abandon():
-            if olt.state() == States.DISCONNECTED or olt.state() == States.FETCH_VERSION:
-                olt.run()
-                olt = olt.transition()
-            elif olt.state() == States.CONNECTED:
-                olt.run()
-                break
-        if olt.abandon():
-            #TODO Add more info here
-            log.info('Disconnecting this OLT')
-            self.stop()
-        self.olt = olt
+        self.olt.run()
 
 
-    def __obtain_descriptor(self):
-        layer = PAS5211MsgGetOltVersionResponse.name
-        pkt = self.olt.send_msg(PAS5211MsgGetOltVersion())
-        return Adapter(
-            id='ruby-{}'.format(olt_conf['olts']['id']),
-            vendor='Celestica',
-            version='{}.{}.{}'.format(pkt[layer].major_firmware_version,
-                                      pkt[layer].minor_firmware_version,
-                                      pkt[layer].build_firmware_version))
+
 
diff --git a/voltha/adapters/microsemi/StateMachine.py b/voltha/adapters/microsemi/StateMachine.py
deleted file mode 100644
index 91d85bf..0000000
--- a/voltha/adapters/microsemi/StateMachine.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#
-# Copyright 2016 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.
-#
-
-"""
-Base OLT State machine class
-"""
-import time
-
-from structlog import get_logger
-from twisted.internet import reactor, task
-from voltha.adapters.microsemi.PAS5211 import PAS5211MsgGetProtocolVersion, PAS5211MsgGetOltVersion
-
-log = get_logger()
-
-class States(object):
-    DISCONNECTED = 0
-    FETCH_VERSION = 1
-    CONNECTED = 2
-
-# TODO convert to scapy automata
-class State(object):
-
-    def __init__(self):
-        pass
-
-    """
-    Attempt an operation towards the OLT
-    """
-    def run(self):
-        raise NotImplementedError()
-
-    """
-    Dictates which state to transtion to.
-    Predicated on the run operation to be successful.
-    """
-    def transition(self):
-        raise NotImplementedError()
-
-    """
-    Returns the current state name
-    """
-    def state(self):
-        raise NotImplementedError()
-
-    """
-    Returns any useful information for the given State
-    """
-    def value(self):
-        raise NotImplementedError()
-
-    """
-    Sends a message to this olt
-    """
-    def send_msg(self, msg):
-        raise NotImplementedError()
-
-    """
-    Disconnected an OLT.
-    """
-    def disconnect(self):
-        raise NotImplementedError()
-
-    """
-    Indicates whether to abandon trying to connect.
-    """
-    def abandon(self):
-        raise  NotImplementedError()
-
-"""
-Represents an OLT in disconnected or pre init state.
-"""
-class Disconnected(State):
-
-    def __init__(self, pas_comm, retry=3):
-        self.comm = pas_comm
-        self.completed = False
-        self.packet = None
-        self.retry = retry
-        self.attempt = 1
-
-    def run(self):
-        self.packet = self.comm.communicate(PAS5211MsgGetProtocolVersion())
-        if self.packet is not None:
-            self.packet.show()
-            self.completed = True
-        else:
-            if self.attempt <= self.retry:
-                time.sleep(self.attempt)
-                self.attempt += 1
-        return self.completed
-
-    def transition(self):
-        if self.completed:
-            return Fetch_Version(self.comm)
-        else:
-            return self
-
-    def state(self):
-        return States.DISCONNECTED
-
-    def value(self):
-        # TODO return a nicer value than the packet.
-        return self.packet
-
-    def send_msg(self, msg):
-        raise NotImplementedError()
-
-    def disconnect(self):
-        pass
-
-    def abandon(self):
-        return self.attempt > self.retry
-
-"""
-Fetches the OLT version
-"""
-class Fetch_Version(State):
-    def __init__(self, pas_comm):
-        self.comm = pas_comm
-        self.completed = False
-        self.packet = None
-
-    def run(self):
-        self.packet = self.comm.communicate(PAS5211MsgGetOltVersion())
-        if self.packet is not None:
-            self.packet.show()
-            self.completed = True
-        return self.completed
-
-    def transition(self):
-        if self.completed:
-            return Connected(self.comm)
-        else:
-            return self
-
-    def state(self):
-        return States.FETCH_VERSION
-
-    def value(self):
-        # TODO return a nicer value than the packet.
-        return self.packet
-
-    def send_msg(self, msg):
-        raise NotImplementedError()
-
-    def disconnect(self):
-        raise NotImplementedError()
-
-    def abandon(self):
-        return False
-
-
-"""
-OLT is in connected State
-"""
-class Connected(State):
-    def __init__(self, pas_comm):
-        self.comm = pas_comm
-        self.completed = False
-        self.packet = None
-        self.scheduled = False
-        self.scheduledTask = task.LoopingCall(self.keepalive)
-
-    def run(self):
-        if not self.scheduled:
-            self.scheduled = True
-            self.scheduledTask.start(1.0)
-
-    def transition(self):
-        if self.completed:
-            return Disconnected(self.comm)
-        else:
-            return self
-
-    def state(self):
-        return States.CONNECTED
-
-    def value(self):
-        # TODO return a nicer value than the packet.
-        return self.packet
-
-    def send_msg(self, msg):
-        return self.comm.communicate(msg)
-
-    def keepalive(self):
-        if self.completed:
-            log.info('OLT has been disconnected')
-            return
-        self.packet = self.comm.communicate(PAS5211MsgGetOltVersion())
-        if self.packet is None:
-            self.completed = True
-
-    def disconnect(self):
-        print "Disconnecting OLT"
-        if self.scheduled:
-            self.completed = True
-            self.scheduledTask.stop()
-        return self.transition()
-
-    def abandon(self):
-        return False
\ No newline at end of file
diff --git a/voltha/adapters/microsemi/chat.py b/voltha/adapters/microsemi/chat.py
index cc69731..f4902ed 100755
--- a/voltha/adapters/microsemi/chat.py
+++ b/voltha/adapters/microsemi/chat.py
@@ -629,7 +629,7 @@
         self.finished = False
 
     def start(self):
-        self.sock = s = conf.L2listen( type=ETH_P_ALL, iface=self.iface, filter='inbound')
+        self.sock = s = conf.L2listen(type=ETH_P_ALL, iface=self.iface, filter='inbound')
         while not self.finished:
             try:
                 sniffed = sniff(1, iface=self.iface, timeout=1, opened_socket=s)
diff --git a/voltha/adapters/microsemi/sniff.py b/voltha/adapters/microsemi/sniff.py
index 7ebf950..23cb7ee 100755
--- a/voltha/adapters/microsemi/sniff.py
+++ b/voltha/adapters/microsemi/sniff.py
@@ -420,7 +420,7 @@
 
 class PAS5211MsgSetOltOpticsResponse(PAS5211Msg):
     name = "PAS5211MsgSetOltOpticsResponse"
-    fields_desc = [ ]
+    fields_desc = []
 
 
 class PAS5211MsgSetOpticsIoControl(PAS5211Msg):
@@ -440,6 +440,8 @@
     name = "PAS5211MsgSetOpticsIoControlResponse"
     fields_desc = [ ]
 
+    def extract_padding(self, p):
+        return "", p
 
 class PAS5211MsgSetGeneralParam(PAS5211Msg):
     opcode = 164