[SEBA-434] Replacing omci-sim with omci-lib-go

Change-Id: I499afc9ec49bb483467ea93bd6ce3077dd0ccc6e
diff --git a/internal/bbsim/devices/messageTypes.go b/internal/bbsim/devices/messageTypes.go
deleted file mode 100644
index 144e1b9..0000000
--- a/internal/bbsim/devices/messageTypes.go
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
-
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package devices
-
-import (
-	"github.com/google/gopacket"
-	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
-	"github.com/opencord/voltha-protos/v4/go/openolt"
-	"net"
-)
-
-type MessageType int
-
-const (
-	OltIndication     MessageType = 0
-	NniIndication     MessageType = 1
-	PonIndication     MessageType = 2
-	OnuDiscIndication MessageType = 3
-	OnuIndication     MessageType = 4
-	OMCI              MessageType = 5
-	FlowAdd           MessageType = 6
-	FlowRemoved       MessageType = 18
-	StartEAPOL        MessageType = 7
-	StartDHCP         MessageType = 8
-	OnuPacketOut      MessageType = 9
-
-	// BBR messages
-	OmciIndication MessageType = 10 // this are OMCI messages going from the OLT to VOLTHA
-	SendEapolFlow  MessageType = 11
-	SendDhcpFlow   MessageType = 12
-	OnuPacketIn    MessageType = 13
-
-	//IGMP
-	IGMPMembershipReportV2 MessageType = 14 // Version 2 Membership Report (JOIN)
-	IGMPLeaveGroup         MessageType = 15 // Leave Group
-
-	AlarmIndication        MessageType = 16 // message data is an openolt.AlarmIndication
-	IGMPMembershipReportV3 MessageType = 17 // Version 3 Membership Report
-)
-
-func (m MessageType) String() string {
-	names := [...]string{
-		"OltIndication",
-		"NniIndication",
-		"PonIndication",
-		"OnuDiscIndication",
-		"OnuIndication",
-		"OMCI",
-		"FlowAdd",
-		"StartEAPOL",
-		"StartDHCP",
-		"OnuPacketOut",
-		"OmciIndication",
-		"SendEapolFlow",
-		"SendDhcpFlow",
-		"OnuPacketIn",
-		"IGMPMembershipReportV2",
-		"IGMPLeaveGroup",
-		"IGMPMembershipReportV3",
-		"FlowRemoved",
-	}
-	return names[m]
-}
-
-type Message struct {
-	Type MessageType
-	Data interface{}
-}
-
-type OltIndicationMessage struct {
-	OperState OperState
-}
-
-type NniIndicationMessage struct {
-	OperState OperState
-	NniPortID uint32
-}
-
-type PonIndicationMessage struct {
-	OperState OperState
-	PonPortID uint32
-}
-
-type OnuDiscIndicationMessage struct {
-	OperState OperState
-	Onu       *Onu
-}
-
-type OnuIndicationMessage struct {
-	OperState OperState
-	PonPortID uint32
-	OnuID     uint32
-	OnuSN     *openolt.SerialNumber
-}
-
-type OmciMessage struct {
-	OnuSN   *openolt.SerialNumber
-	OnuID   uint32
-	omciMsg *openolt.OmciMsg
-}
-
-type OmciIndicationMessage struct {
-	OnuSN   *openolt.SerialNumber
-	OnuID   uint32
-	OmciInd *openolt.OmciIndication
-}
-
-type OnuFlowUpdateMessage struct {
-	PonPortID uint32
-	OnuID     uint32
-	Flow      *openolt.Flow
-}
-
-type PacketMessage struct {
-	PonPortID uint32
-	OnuID     uint32
-}
-
-type OnuPacketMessage struct {
-	IntfId     uint32
-	OnuId      uint32
-	Packet     gopacket.Packet
-	Type       packetHandlers.PacketType
-	MacAddress net.HardwareAddr
-	GemPortId  uint32 // this is used by BBR
-}
-
-type IgmpMessage struct {
-	GroupAddress string
-}
-
-type OperState int
-
-const (
-	UP   OperState = iota
-	DOWN           // The device has been discovered, but not yet activated
-)
-
-func (m OperState) String() string {
-	names := [...]string{
-		"up",
-		"down",
-	}
-	return names[m]
-}
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 9e26ad2..6540a56 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -21,8 +21,10 @@
 	"encoding/hex"
 	"fmt"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/ext/config"
 	"net"
+	"strconv"
 	"sync"
 	"time"
 
@@ -31,7 +33,6 @@
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/common"
-	omcisim "github.com/opencord/omci-sim"
 	common_protos "github.com/opencord/voltha-protos/v4/go/common"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"github.com/opencord/voltha-protos/v4/go/tech_profile"
@@ -57,7 +58,7 @@
 	NumPon               int
 	NumOnuPerPon         int
 	InternalState        *fsm.FSM
-	channel              chan Message
+	channel              chan types.Message
 	dhcpServer           dhcp.DHCPServerIf
 	Flows                sync.Map
 	Delay                int
@@ -230,7 +231,7 @@
 	}
 
 	// create new channel for processOltMessages Go routine
-	o.channel = make(chan Message)
+	o.channel = make(chan types.Message)
 
 	// FIXME we are assuming we have only one NNI
 	if o.Nnis[0] != nil {
@@ -272,10 +273,10 @@
 		for _, pon := range o.Pons {
 			if pon.InternalState.Current() == "enabled" {
 				// disable PONs
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: DOWN,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.DOWN,
 						PonPortID: pon.ID,
 					},
 				}
@@ -388,35 +389,33 @@
 	go o.processOltMessages(o.enableContext, stream, &wg)
 
 	// enable the OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: UP,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.UP,
 		},
 	}
 	o.channel <- oltMsg
 
 	// send NNI Port Indications
 	for _, nni := range o.Nnis {
-		msg := Message{
-			Type: NniIndication,
-			Data: NniIndicationMessage{
-				OperState: UP,
+		msg := types.Message{
+			Type: types.NniIndication,
+			Data: types.NniIndicationMessage{
+				OperState: types.UP,
 				NniPortID: nni.ID,
 			},
 		}
 		o.channel <- msg
 	}
 
-	go o.processOmciMessages(o.enableContext, stream, &wg)
-
 	if rebootFlag {
 		for _, pon := range o.Pons {
 			if pon.InternalState.Current() == "disabled" {
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: UP,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.UP,
 						PonPortID: pon.ID,
 					},
 				}
@@ -431,10 +430,10 @@
 		if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
 			// send PON Port indications
 			for _, pon := range o.Pons {
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: UP,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.UP,
 						PonPortID: pon.ID,
 					},
 				}
@@ -453,43 +452,6 @@
 	wg.Wait()
 }
 
-func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
-	ch := omcisim.GetChannel()
-
-	oltLogger.Debug("Starting OMCI Indication Channel")
-
-loop:
-	for {
-		select {
-		case <-ctx.Done():
-			oltLogger.Debug("OMCI processing canceled via context")
-			break loop
-		case message, ok := <-ch:
-			if !ok || ctx.Err() != nil {
-				oltLogger.Debug("OMCI processing canceled via channel close")
-				break loop
-			}
-
-			oltLogger.WithFields(log.Fields{
-				"messageType": message.Type,
-				"OnuId":       message.Data.OnuId,
-				"IntfId":      message.Data.IntfId,
-			}).Debug("Received message on OMCI Sim channel")
-
-			onuId := message.Data.OnuId
-			intfId := message.Data.IntfId
-			onu, err := o.FindOnuById(intfId, onuId)
-			if err != nil {
-				oltLogger.Errorf("Failed to find onu: %v", err)
-				continue
-			}
-			go onu.processOmciMessage(message, stream)
-		}
-	}
-
-	wg.Done()
-}
-
 func (o *OltDevice) periodicPortStats(ctx context.Context) {
 	var portStats *openolt.PortStatistics
 	for {
@@ -525,6 +487,55 @@
 
 // Helpers method
 
+func (o *OltDevice) SetAlarm(interfaceId uint32, interfaceType string, alarmStatus string) error {
+
+	switch interfaceType {
+	case "nni":
+		if !o.HasNni(interfaceId) {
+			return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" NNI not present in olt")
+		}
+
+	case "pon":
+		if !o.HasPon(interfaceId) {
+			return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" PON not present in olt")
+		}
+	}
+
+	alarmIndication := &openolt.AlarmIndication{
+		Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
+			Status: alarmStatus,
+			IntfId: InterfaceIDToPortNo(interfaceId, interfaceType),
+		}},
+	}
+
+	msg := types.Message{
+		Type: types.AlarmIndication,
+		Data: alarmIndication,
+	}
+
+	o.channel <- msg
+
+	return nil
+}
+
+func (o *OltDevice) HasNni(id uint32) bool {
+	for _, intf := range o.Nnis {
+		if intf.ID == id {
+			return true
+		}
+	}
+	return false
+}
+
+func (o *OltDevice) HasPon(id uint32) bool {
+	for _, intf := range o.Pons {
+		if intf.ID == id {
+			return true
+		}
+	}
+	return false
+}
+
 func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
 	for _, pon := range o.Pons {
 		if pon.ID == id {
@@ -555,7 +566,7 @@
 	}).Debug("Sent Indication_AlarmInd")
 }
 
-func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendOltIndication(msg types.OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
 	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
 		oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
@@ -567,9 +578,9 @@
 	}).Debug("Sent Indication_OltInd")
 }
 
-func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendNniIndication(msg types.NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	nni, _ := o.getNniById(msg.NniPortID)
-	if msg.OperState == UP {
+	if msg.OperState == types.UP {
 		if err := nni.OperState.Event("enable"); err != nil {
 			log.WithFields(log.Fields{
 				"Type":      nni.Type,
@@ -577,7 +588,7 @@
 				"OperState": nni.OperState.Current(),
 			}).Errorf("Can't move NNI Port to enabled state: %v", err)
 		}
-	} else if msg.OperState == DOWN {
+	} else if msg.OperState == types.DOWN {
 		if err := nni.OperState.Event("disable"); err != nil {
 			log.WithFields(log.Fields{
 				"Type":      nni.Type,
@@ -685,26 +696,26 @@
 			}).Trace("Received message")
 
 			switch message.Type {
-			case OltIndication:
-				msg, _ := message.Data.(OltIndicationMessage)
-				if msg.OperState == UP {
+			case types.OltIndication:
+				msg, _ := message.Data.(types.OltIndicationMessage)
+				if msg.OperState == types.UP {
 					_ = o.InternalState.Event("enable")
 					_ = o.OperState.Event("enable")
-				} else if msg.OperState == DOWN {
+				} else if msg.OperState == types.DOWN {
 					_ = o.InternalState.Event("disable")
 					_ = o.OperState.Event("disable")
 				}
 				o.sendOltIndication(msg, stream)
-			case AlarmIndication:
+			case types.AlarmIndication:
 				alarmInd, _ := message.Data.(*openolt.AlarmIndication)
 				o.sendAlarmIndication(alarmInd, stream)
-			case NniIndication:
-				msg, _ := message.Data.(NniIndicationMessage)
+			case types.NniIndication:
+				msg, _ := message.Data.(types.NniIndicationMessage)
 				o.sendNniIndication(msg, stream)
-			case PonIndication:
-				msg, _ := message.Data.(PonIndicationMessage)
+			case types.PonIndication:
+				msg, _ := message.Data.(types.PonIndicationMessage)
 				pon, _ := o.GetPonById(msg.PonPortID)
-				if msg.OperState == UP {
+				if msg.OperState == types.UP {
 					if err := pon.OperState.Event("enable"); err != nil {
 						oltLogger.WithFields(log.Fields{
 							"IntfId": msg.PonPortID,
@@ -717,7 +728,7 @@
 							"Err":    err,
 						}).Error("Can't Enable Internal state for PON Port")
 					}
-				} else if msg.OperState == DOWN {
+				} else if msg.OperState == types.DOWN {
 					if err := pon.OperState.Event("disable"); err != nil {
 						oltLogger.WithFields(log.Fields{
 							"IntfId": msg.PonPortID,
@@ -873,10 +884,10 @@
 	for _, pon := range o.Pons {
 		if pon.InternalState.Current() == "enabled" {
 			// disable PONs
-			msg := Message{
-				Type: PonIndication,
-				Data: PonIndicationMessage{
-					OperState: DOWN,
+			msg := types.Message{
+				Type: types.PonIndication,
+				Data: types.PonIndicationMessage{
+					OperState: types.DOWN,
 					PonPortID: pon.ID,
 				},
 			}
@@ -888,10 +899,10 @@
 	// The reason for that is in-band management
 
 	// disable OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: DOWN,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.DOWN,
 		},
 	}
 	o.channel <- oltMsg
@@ -903,10 +914,10 @@
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
 
-	msg := Message{
-		Type: PonIndication,
-		Data: PonIndicationMessage{
-			OperState: DOWN,
+	msg := types.Message{
+		Type: types.PonIndication,
+		Data: types.PonIndicationMessage{
+			OperState: types.DOWN,
 			PonPortID: ponID,
 		},
 	}
@@ -914,8 +925,8 @@
 
 	for _, onu := range pon.Onus {
 
-		onuIndication := OnuIndicationMessage{
-			OperState: DOWN,
+		onuIndication := types.OnuIndicationMessage{
+			OperState: types.DOWN,
 			PonPortID: ponID,
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
@@ -939,10 +950,10 @@
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
 
-	msg := Message{
-		Type: PonIndication,
-		Data: PonIndicationMessage{
-			OperState: UP,
+	msg := types.Message{
+		Type: types.PonIndication,
+		Data: types.PonIndicationMessage{
+			OperState: types.UP,
 			PonPortID: ponID,
 		},
 	}
@@ -950,8 +961,8 @@
 
 	for _, onu := range pon.Onus {
 
-		onuIndication := OnuIndicationMessage{
-			OperState: UP,
+		onuIndication := types.OnuIndicationMessage{
+			OperState: types.UP,
 			PonPortID: ponID,
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
@@ -1030,9 +1041,9 @@
 			}
 		}
 
-		msg := Message{
-			Type: FlowAdd,
-			Data: OnuFlowUpdateMessage{
+		msg := types.Message{
+			Type: types.FlowAdd,
+			Data: types.OnuFlowUpdateMessage{
 				PonPortID: pon.ID,
 				OnuID:     onu.ID,
 				Flow:      flow,
@@ -1107,9 +1118,9 @@
 			return nil, err
 		}
 
-		msg := Message{
-			Type: FlowRemoved,
-			Data: OnuFlowUpdateMessage{
+		msg := types.Message{
+			Type: types.FlowRemoved,
+			Data: types.OnuFlowUpdateMessage{
 				Flow: flow,
 			},
 		}
@@ -1193,12 +1204,12 @@
 		"OnuId":  onu.ID,
 		"OnuSn":  onu.Sn(),
 	}).Tracef("Received OmciMsgOut")
-	msg := Message{
-		Type: OMCI,
-		Data: OmciMessage{
+	msg := types.Message{
+		Type: types.OMCI,
+		Data: types.OmciMessage{
 			OnuSN:   onu.SerialNumber,
 			OnuID:   onu.ID,
-			omciMsg: omci_msg,
+			OmciMsg: omci_msg,
 		},
 	}
 	onu.Channel <- msg
@@ -1254,9 +1265,9 @@
 		return new(openolt.Empty), nil
 	}
 
-	msg := Message{
-		Type: OnuPacketOut,
-		Data: OnuPacketMessage{
+	msg := types.Message{
+		Type: types.OnuPacketOut,
+		Data: types.OnuPacketMessage{
 			IntfId:     onuPkt.IntfId,
 			OnuId:      onuPkt.OnuId,
 			Packet:     rawpkt,
@@ -1291,20 +1302,20 @@
 	publishEvent("OLT-reenable-received", -1, -1, "")
 
 	// enable OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: UP,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.UP,
 		},
 	}
 	o.channel <- oltMsg
 
 	for _, pon := range o.Pons {
 		if pon.InternalState.Current() == "disabled" {
-			msg := Message{
-				Type: PonIndication,
-				Data: PonIndicationMessage{
-					OperState: UP,
+			msg := types.Message{
+				Type: types.PonIndication,
+				Data: types.PonIndicationMessage{
+					OperState: types.UP,
 					PonPortID: pon.ID,
 				},
 			}
@@ -1397,17 +1408,6 @@
 	return new(openolt.Empty), nil
 }
 
-// assumes caller has properly formulated an openolt.AlarmIndication
-func (o *OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
-	msg := Message{
-		Type: AlarmIndication,
-		Data: ind,
-	}
-
-	o.channel <- msg
-	return nil
-}
-
 func (o *OltDevice) PerformGroupOperation(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
 	oltLogger.WithFields(log.Fields{
 		"GroupId": group.GroupId,
diff --git a/internal/bbsim/devices/olt_test.go b/internal/bbsim/devices/olt_test.go
index 0081ffa..154942b 100644
--- a/internal/bbsim/devices/olt_test.go
+++ b/internal/bbsim/devices/olt_test.go
@@ -17,6 +17,7 @@
 package devices
 
 import (
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/bbsim/internal/common"
 	"net"
 	"testing"
@@ -202,7 +203,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg1 := OnuFlowUpdateMessage{
+	msg1 := types.OnuFlowUpdateMessage{
 		OnuID:     onu1.ID,
 		PonPortID: onu1.PonPortID,
 		Flow:      &flow1,
@@ -214,7 +215,7 @@
 		FlowId:     72,
 		Classifier: &openolt.Classifier{},
 	}
-	msg2 := OnuFlowUpdateMessage{
+	msg2 := types.OnuFlowUpdateMessage{
 		OnuID:     onu2.ID,
 		PonPortID: onu2.PonPortID,
 		Flow:      &flow2,
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index b85c804..822ec6b 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -20,20 +20,24 @@
 	"context"
 	"encoding/hex"
 	"fmt"
+	pb "github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsim/alarmsim"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	me "github.com/opencord/omci-lib-go/generated"
+	"strconv"
+
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
 	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
 	"net"
-
 	"time"
 
-	"github.com/cboling/omci"
 	"github.com/google/gopacket/layers"
 	"github.com/jpillora/backoff"
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/common"
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
-	omcisim "github.com/opencord/omci-sim"
+	"github.com/opencord/omci-lib-go"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"github.com/opencord/voltha-protos/v4/go/tech_profile"
 	log "github.com/sirupsen/logrus"
@@ -72,7 +76,7 @@
 	OperState    *fsm.FSM
 	SerialNumber *openolt.SerialNumber
 
-	Channel chan Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
+	Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
 
 	// OMCI params
 	tid       uint16
@@ -143,7 +147,7 @@
 			},
 			"enter_initialized": func(e *fsm.Event) {
 				// create new channel for ProcessOnuMessages Go routine
-				o.Channel = make(chan Message, 2048)
+				o.Channel = make(chan bbsim.Message, 2048)
 
 				if err := o.OperState.Event("enable"); err != nil {
 					onuLogger.WithFields(log.Fields{
@@ -159,22 +163,21 @@
 				}
 			},
 			"enter_discovered": func(e *fsm.Event) {
-				msg := Message{
-					Type: OnuDiscIndication,
-					Data: OnuDiscIndicationMessage{
-						Onu:       &o,
-						OperState: UP,
+				msg := bbsim.Message{
+					Type: bbsim.OnuDiscIndication,
+					Data: bbsim.OnuDiscIndicationMessage{
+						OperState: bbsim.UP,
 					},
 				}
 				o.Channel <- msg
 			},
 			"enter_enabled": func(event *fsm.Event) {
-				msg := Message{
-					Type: OnuIndication,
-					Data: OnuIndicationMessage{
+				msg := bbsim.Message{
+					Type: bbsim.OnuIndication,
+					Data: bbsim.OnuIndicationMessage{
 						OnuSN:     o.SerialNumber,
 						PonPortID: o.PonPortID,
-						OperState: UP,
+						OperState: bbsim.UP,
 					},
 				}
 				o.Channel <- msg
@@ -201,12 +204,12 @@
 				}
 
 				// send the OnuIndication DOWN event
-				msg := Message{
-					Type: OnuIndication,
-					Data: OnuIndicationMessage{
+				msg := bbsim.Message{
+					Type: bbsim.OnuIndication,
+					Data: bbsim.OnuIndicationMessage{
 						OnuSN:     o.SerialNumber,
 						PonPortID: o.PonPortID,
-						OperState: DOWN,
+						OperState: bbsim.DOWN,
 					},
 				}
 				o.Channel <- msg
@@ -223,14 +226,14 @@
 			},
 			// BBR states
 			"enter_eapol_flow_sent": func(e *fsm.Event) {
-				msg := Message{
-					Type: SendEapolFlow,
+				msg := bbsim.Message{
+					Type: bbsim.SendEapolFlow,
 				}
 				o.Channel <- msg
 			},
 			"enter_dhcp_flow_sent": func(e *fsm.Event) {
-				msg := Message{
-					Type: SendDhcpFlow,
+				msg := bbsim.Message{
+					Type: bbsim.SendDhcpFlow,
 				}
 				o.Channel <- msg
 			},
@@ -280,26 +283,45 @@
 			}).Tracef("Received message on ONU Channel")
 
 			switch message.Type {
-			case OnuDiscIndication:
-				msg, _ := message.Data.(OnuDiscIndicationMessage)
+			case bbsim.OnuDiscIndication:
+				msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
 				// NOTE we need to slow down and send ONU Discovery Indication in batches to better emulate a real scenario
 				time.Sleep(o.DiscoveryDelay)
 				o.sendOnuDiscIndication(msg, stream)
-			case OnuIndication:
-				msg, _ := message.Data.(OnuIndicationMessage)
+			case bbsim.OnuIndication:
+				msg, _ := message.Data.(bbsim.OnuIndicationMessage)
 				o.sendOnuIndication(msg, stream)
-			case OMCI:
-				msg, _ := message.Data.(OmciMessage)
-				o.handleOmciMessage(msg, stream)
-			case FlowAdd:
-				msg, _ := message.Data.(OnuFlowUpdateMessage)
+			case bbsim.OMCI:
+				msg, _ := message.Data.(bbsim.OmciMessage)
+				o.handleOmciRequest(msg, stream)
+			case bbsim.UniStatusAlarm:
+				msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
+				pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
+				if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"SerialNumber": o.Sn(),
+						"omciPacket":   pkt,
+						"adminState":   msg.AdminState,
+						"entityID":     msg.EntityID,
+					}).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
+				}
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+					"omciPacket":   pkt,
+					"adminState":   msg.AdminState,
+					"entityID":     msg.EntityID,
+				}).Trace("UNI-Link-alarm-sent")
+			case bbsim.FlowAdd:
+				msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
 				o.handleFlowAdd(msg)
-			case FlowRemoved:
-				msg, _ := message.Data.(OnuFlowUpdateMessage)
+			case bbsim.FlowRemoved:
+				msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
 				o.handleFlowRemove(msg)
-			case OnuPacketOut:
+			case bbsim.OnuPacketOut:
 
-				msg, _ := message.Data.(OnuPacketMessage)
+				msg, _ := message.Data.(bbsim.OnuPacketMessage)
 
 				onuLogger.WithFields(log.Fields{
 					"IntfId":  msg.IntfId,
@@ -333,11 +355,11 @@
 					}
 				}
 
-			case OnuPacketIn:
+			case bbsim.OnuPacketIn:
 				// NOTE we only receive BBR packets here.
 				// Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
 				// in the DHCP case VOLTHA only act as a proxy, the behaviour is completely different thus we have a dhcp.HandleNextBbrPacket
-				msg, _ := message.Data.(OnuPacketMessage)
+				msg, _ := message.Data.(bbsim.OnuPacketMessage)
 
 				log.WithFields(log.Fields{
 					"IntfId":  msg.IntfId,
@@ -351,12 +373,12 @@
 					_ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
 				}
 				// BBR specific messages
-			case OmciIndication:
-				msg, _ := message.Data.(OmciIndicationMessage)
-				o.handleOmci(msg, client)
-			case SendEapolFlow:
+			case bbsim.OmciIndication:
+				msg, _ := message.Data.(bbsim.OmciIndicationMessage)
+				o.handleOmciResponse(msg, client)
+			case bbsim.SendEapolFlow:
 				o.sendEapolFlow(client)
-			case SendDhcpFlow:
+			case bbsim.SendDhcpFlow:
 				o.sendDhcpFlow(client)
 			default:
 				onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
@@ -369,42 +391,6 @@
 	}).Debug("Stopped handling ONU Indication Channel")
 }
 
-func (o *Onu) processOmciMessage(message omcisim.OmciChMessage, stream openolt.Openolt_EnableIndicationServer) {
-	switch message.Type {
-	case omcisim.UniLinkUp, omcisim.UniLinkDown:
-		onuLogger.WithFields(log.Fields{
-			"OnuId":  message.Data.OnuId,
-			"IntfId": message.Data.IntfId,
-			"Type":   message.Type,
-		}).Debug("UNI Link Alarm")
-		// TODO send to OLT
-
-		omciInd := openolt.OmciIndication{
-			IntfId: message.Data.IntfId,
-			OnuId:  message.Data.OnuId,
-			Pkt:    message.Packet,
-		}
-
-		omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
-		if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-			onuLogger.WithFields(log.Fields{
-				"IntfId":       o.PonPortID,
-				"SerialNumber": o.Sn(),
-				"Type":         message.Type,
-				"omciPacket":   omciInd.Pkt,
-			}).Errorf("Failed to send UNI Link Alarm: %v", err)
-			return
-		}
-
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"Type":         message.Type,
-			"omciPacket":   omciInd.Pkt,
-		}).Debug("UNI Link alarm sent")
-	}
-}
-
 func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
 
 	sn := new(openolt.SerialNumber)
@@ -416,10 +402,10 @@
 	return sn
 }
 
-func (o *Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
-		IntfId:       msg.Onu.PonPortID,
-		SerialNumber: msg.Onu.SerialNumber,
+		IntfId:       o.PonPortID,
+		SerialNumber: o.SerialNumber,
 	}}
 
 	if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
@@ -428,11 +414,11 @@
 	}
 
 	onuLogger.WithFields(log.Fields{
-		"IntfId": msg.Onu.PonPortID,
-		"OnuSn":  msg.Onu.Sn(),
+		"IntfId": o.PonPortID,
+		"OnuSn":  o.Sn(),
 		"OnuId":  o.ID,
 	}).Debug("Sent Indication_OnuDiscInd")
-	publishEvent("ONU-discovery-indication-sent", int32(msg.Onu.PonPortID), int32(o.ID), msg.Onu.Sn())
+	publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
 
 	// after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
 	go func(delay time.Duration) {
@@ -443,7 +429,7 @@
 	}(o.DiscoveryRetryDelay)
 }
 
-func (o *Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	// NOTE voltha returns an ID, but if we use that ID then it complains:
 	// expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
 	// so we're using the internal ID that is 1
@@ -471,17 +457,136 @@
 
 }
 
-func (o *Onu) publishOmciEvent(msg OmciMessage) {
+func (o *Onu) HandleShutdownONU() error {
+
+	dyingGasp := pb.ONUAlarmRequest{
+		AlarmType:    "DYING_GASP",
+		SerialNumber: o.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send Dying Gasp: %s", err.Error())
+		return err
+	}
+
+	losReq := pb.ONUAlarmRequest{
+		AlarmType:    "ONU_ALARM_LOS",
+		SerialNumber: o.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+
+		return err
+	}
+
+	// TODO if it's the last ONU on the PON, then send a PON LOS
+
+	if err := o.InternalState.Event("disable"); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot shutdown ONU: %s", err.Error())
+		return err
+	}
+
+	return nil
+}
+
+func (o *Onu) HandlePowerOnONU() error {
+	intitalState := o.InternalState.Current()
+
+	// initialize the ONU
+	if intitalState == "created" || intitalState == "disabled" {
+		if err := o.InternalState.Event("initialize"); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":  o.ID,
+				"IntfId": o.PonPortID,
+				"OnuSn":  o.Sn(),
+			}).Errorf("Cannot poweron ONU: %s", err.Error())
+			return err
+		}
+	}
+
+	// turn off the LOS Alarm
+	losReq := pb.ONUAlarmRequest{
+		AlarmType:    "ONU_ALARM_LOS",
+		SerialNumber: o.Sn(),
+		Status:       "off",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+		return err
+	}
+
+	// Send a ONU Discovery indication
+	if err := o.InternalState.Event("discover"); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot poweron ONU: %s", err.Error())
+		return err
+	}
+
+	// move o directly to enable state only when its a powercycle case
+	// in case of first time o poweron o will be moved to enable on
+	// receiving ActivateOnu request from openolt adapter
+	if intitalState == "disabled" {
+		if err := o.InternalState.Event("enable"); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":  o.ID,
+				"IntfId": o.PonPortID,
+				"OnuSn":  o.Sn(),
+			}).Errorf("Cannot enable ONU: %s", err.Error())
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (o *Onu) SetAlarm(alarmType string, status string) error {
+	alarmReq := pb.ONUAlarmRequest{
+		AlarmType:    alarmType,
+		SerialNumber: o.Sn(),
+		Status:       status,
+	}
+
+	err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
 	if olt.PublishEvents {
-		_, _, msgType, _, _, _, err := omcisim.ParsePkt(HexDecode(msg.omciMsg.Pkt))
+		_, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
 		if err != nil {
 			log.Errorf("error in getting msgType %v", err)
 			return
 		}
-		if msgType == omcisim.MibUpload {
+		if omciMsg.MessageType == omci.MibUploadRequestType {
 			o.seqNumber = 0
 			publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
-		} else if msgType == omcisim.MibUploadNext {
+		} else if omciMsg.MessageType == omci.MibUploadNextRequestType {
 			o.seqNumber++
 			if o.seqNumber > 290 {
 				publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
@@ -491,8 +596,8 @@
 }
 
 // Create a TestResponse packet and send it
-func (o *Onu) sendTestResult(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
-	resp, err := omcilib.BuildTestResult(HexDecode(msg.omciMsg.Pkt))
+func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
+	resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
 	if err != nil {
 		return err
 	}
@@ -504,12 +609,6 @@
 
 	omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
 	if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("send TestResult omcisim indication failed: %v", err)
 		return err
 	}
 	onuLogger.WithFields(log.Fields{
@@ -521,57 +620,151 @@
 	return nil
 }
 
-func (o *Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
+// and generate the appropriate response to it
+func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+
+	omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+			"omciPacket":   msg.OmciMsg.Pkt,
+		}).Error("cannot-parse-OMCI-packet")
+	}
 
 	onuLogger.WithFields(log.Fields{
+		"omciMsgType":  omciMsg.MessageType,
+		"transCorrId":  strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"DeviceIdent":  omciMsg.DeviceIdentifier,
 		"IntfId":       o.PonPortID,
 		"SerialNumber": o.Sn(),
-		"omciPacket":   msg.omciMsg.Pkt,
-	}).Tracef("Received OMCI message")
+	}).Trace("omci-message-decoded")
+
+	var responsePkt []byte
+	switch omciMsg.MessageType {
+	case omci.MibResetRequestType:
+		responsePkt, _ = omcilib.CreateMibResetResponse(omciMsg.TransactionID)
+	case omci.MibUploadRequestType:
+		responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
+	case omci.MibUploadNextRequestType:
+		responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg)
+	case omci.GetRequestType:
+		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg)
+	case omci.SetRequestType:
+		responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg)
+
+		msgObj, _ := omcilib.ParseSetRequest(omciPkt)
+		switch msgObj.EntityClass {
+		case me.PhysicalPathTerminationPointEthernetUniClassID:
+			// if we're Setting a PPTP state
+			// we need to send the appropriate alarm
+
+			if msgObj.EntityInstance == 257 {
+				// for now we're only caring about the first UNI
+				// NOTE that the EntityID for the UNI port is for now hardcoded in
+				// omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
+				// are reported during the MIB Upload sequence
+				adminState := msgObj.Attributes["AdministrativeState"].(uint8)
+				msg := bbsim.Message{
+					Type: bbsim.UniStatusAlarm,
+					Data: bbsim.UniStatusAlarmMessage{
+						OnuSN:      o.SerialNumber,
+						OnuID:      o.ID,
+						AdminState: adminState,
+						EntityID:   msgObj.EntityInstance,
+					},
+				}
+				o.Channel <- msg
+			}
+		}
+	case omci.CreateRequestType:
+		responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg)
+	case omci.DeleteRequestType:
+		responsePkt, _ = omcilib.CreateDeleteResponse(omciPkt, omciMsg)
+	case omci.RebootRequestType:
+
+		responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
+
+		// powercycle the ONU
+		go func() {
+			// we run this in a separate goroutine so that
+			// the RebootRequestResponse is sent to VOLTHA
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Debug("shutting-down-onu-for-omci-reboot")
+			_ = o.HandleShutdownONU()
+			time.Sleep(10 * time.Second)
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Debug("power-on-onu-for-omci-reboot")
+			_ = o.HandlePowerOnONU()
+		}()
+	case omci.TestRequestType:
+
+		// Test message is special, it requires sending two packets:
+		//     first packet: TestResponse, says whether test was started successully, handled by omci-sim
+		//     second packet, TestResult, reports the result of running the self-test
+		// TestResult can come some time after a TestResponse
+		//     TODO: Implement some delay between the TestResponse and the TestResult
+		isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
+		if (err == nil) && (isTest) {
+			if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+					"omciPacket":   msg.OmciMsg.Pkt,
+					"msg":          msg,
+					"err":          sendErr,
+				}).Error("send-TestResult-indication-failed")
+			}
+		}
+
+	default:
+		log.WithFields(log.Fields{
+			"omciMsgType":  omciMsg.MessageType,
+			"transCorrId":  omciMsg.TransactionID,
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+		}).Warnf("OMCI-message-not-supported")
+	}
+
+	if responsePkt != nil {
+		if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+				"omciPacket":   responsePkt,
+				"omciMsgType":  omciMsg.MessageType,
+				"transCorrId":  omciMsg.TransactionID,
+			}).Errorf("failed-to-send-omci-message: %v", err)
+		}
+	}
 
 	o.publishOmciEvent(msg)
+}
 
-	var omciInd openolt.OmciIndication
-	respPkt, err := omcisim.OmciSim(o.PonPort.Olt.ID, o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
-	if err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("Error handling OMCI message %v", msg)
-		return
+// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
+func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
+	indication := &openolt.Indication_OmciInd{
+		OmciInd: &openolt.OmciIndication{
+			IntfId: o.PonPortID,
+			OnuId:  o.ID,
+			Pkt:    responsePkt,
+		},
 	}
-
-	omciInd.IntfId = o.PonPortID
-	omciInd.OnuId = o.ID
-	omciInd.Pkt = respPkt
-
-	omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
-	if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("send omcisim indication failed: %v", err)
-		return
+	if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
+		return fmt.Errorf("failed-to-send-omci-message: %v", err)
 	}
 	onuLogger.WithFields(log.Fields{
 		"IntfId":       o.PonPortID,
 		"SerialNumber": o.Sn(),
-		"omciPacket":   omciInd.Pkt,
-	}).Tracef("Sent OMCI message")
-
-	// Test message is special, it requires sending two packets:
-	//     first packet: TestResponse, says whether test was started successully, handled by omci-sim
-	//     second packet, TestResult, reports the result of running the self-test
-	// TestResult can come some time after a TestResponse
-	//     TODO: Implement some delay between the TestResponse and the TestResult
-	isTest, err := omcilib.IsTestRequest(HexDecode(msg.omciMsg.Pkt))
-	if (err == nil) && (isTest) {
-		_ = o.sendTestResult(msg, stream)
-	}
+		"omciPacket":   indication.OmciInd.Pkt,
+		"transCorrId":  txId,
+	}).Trace("omci-message-sent")
+	return nil
 }
 
 func (o *Onu) storePortNumber(portNo uint32) {
@@ -602,7 +795,7 @@
 	o.ID = id
 }
 
-func (o *Onu) handleFlowAdd(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
 	onuLogger.WithFields(log.Fields{
 		"Cookie":            msg.Flow.Cookie,
 		"DstPort":           msg.Flow.Classifier.DstPort,
@@ -667,7 +860,7 @@
 	}
 }
 
-func (o *Onu) handleFlowRemove(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
 	onuLogger.WithFields(log.Fields{
 		"IntfId":       o.PonPortID,
 		"OnuId":        o.ID,
@@ -700,19 +893,6 @@
 	}
 }
 
-// HexDecode converts the hex encoding to binary
-func HexDecode(pkt []byte) []byte {
-	p := make([]byte, len(pkt)/2)
-	for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
-		// Go figure this ;)
-		u := (pkt[i] & 15) + (pkt[i]>>6)*9
-		l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
-		p[j] = u<<4 + l
-	}
-	onuLogger.Tracef("Omci decoded: %x.", p)
-	return p
-}
-
 // BBR methods
 
 func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
@@ -762,24 +942,36 @@
 	sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
 }
 
-func (o *Onu) handleOmci(msg OmciIndicationMessage, client openolt.OpenoltClient) {
-	msgType, packet := omcilib.DecodeOmci(msg.OmciInd.Pkt)
+// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
+func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
+
+	// we need to encode the packet in HEX
+	pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
+	hex.Encode(pkt, msg.OmciInd.Pkt)
+	packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+			"omciPacket":   msg.OmciInd.Pkt,
+		}).Error("BBR Cannot parse OMCI packet")
+	}
 
 	log.WithFields(log.Fields{
 		"IntfId":  msg.OmciInd.IntfId,
 		"OnuId":   msg.OmciInd.OnuId,
-		"OnuSn":   common.OnuSnToString(o.SerialNumber),
+		"OnuSn":   o.Sn(),
 		"Pkt":     msg.OmciInd.Pkt,
-		"msgType": msgType,
+		"msgType": omciMsg.MessageType,
 	}).Trace("ONU Receives OMCI Msg")
-	switch msgType {
+	switch omciMsg.MessageType {
 	default:
 		log.WithFields(log.Fields{
 			"IntfId":  msg.OmciInd.IntfId,
 			"OnuId":   msg.OmciInd.OnuId,
-			"OnuSn":   common.OnuSnToString(o.SerialNumber),
+			"OnuSn":   o.Sn(),
 			"Pkt":     msg.OmciInd.Pkt,
-			"msgType": msgType,
+			"msgType": omciMsg.MessageType,
 		}).Fatalf("unexpected frame: %v", packet)
 	case omci.MibResetResponseType:
 		mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index 1464ae5..e0ad9fe 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -19,6 +19,7 @@
 import (
 	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"gotest.tools/assert"
 	"testing"
@@ -54,7 +55,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -74,7 +75,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -107,7 +108,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -147,7 +148,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -194,7 +195,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -235,7 +236,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -279,7 +280,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -323,7 +324,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -367,7 +368,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -409,7 +410,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -457,7 +458,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index 89eb195..ef6e4a2 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"errors"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/common"
 	"github.com/opencord/voltha-protos/v4/go/ext/config"
 	"time"
@@ -137,7 +138,7 @@
 		},
 	}
 	o.SerialNumber = o.NewSN(0, ponPortId, o.ID)
-	o.Channel = make(chan Message, 10)
+	o.Channel = make(chan types.Message, 10)
 	return &o
 }
 
diff --git a/internal/bbsim/devices/services.go b/internal/bbsim/devices/services.go
index bd4d13c..4391414 100644
--- a/internal/bbsim/devices/services.go
+++ b/internal/bbsim/devices/services.go
@@ -71,9 +71,9 @@
 	EapolState    *fsm.FSM
 	DHCPState     *fsm.FSM
 	IGMPState     *fsm.FSM
-	Channel       chan Message          // drive Service lifecycle
-	PacketCh      chan OnuPacketMessage // handle packets
-	Stream        bbsimTypes.Stream     // the gRPC stream to communicate with the adapter, created in the initialize transition
+	Channel       chan bbsimTypes.Message          // drive Service lifecycle
+	PacketCh      chan bbsimTypes.OnuPacketMessage // handle packets
+	Stream        bbsimTypes.Stream                // the gRPC stream to communicate with the adapter, created in the initialize transition
 }
 
 func NewService(name string, hwAddress net.HardwareAddr, onu *Onu, cTag int, sTag int,
@@ -117,8 +117,8 @@
 
 				service.Stream = stream
 
-				service.PacketCh = make(chan OnuPacketMessage)
-				service.Channel = make(chan Message)
+				service.PacketCh = make(chan bbsimTypes.OnuPacketMessage)
+				service.Channel = make(chan bbsimTypes.Message)
 
 				go service.HandlePackets()
 				go service.HandleChannel()
@@ -153,8 +153,8 @@
 				service.logStateChange("EapolState", e.Src, e.Dst)
 			},
 			"before_start_auth": func(e *fsm.Event) {
-				msg := Message{
-					Type: StartEAPOL,
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.StartEAPOL,
 				}
 				service.Channel <- msg
 			},
@@ -207,8 +207,8 @@
 				service.logStateChange("DHCPState", e.Src, e.Dst)
 			},
 			"before_start_dhcp": func(e *fsm.Event) {
-				msg := Message{
-					Type: StartDHCP,
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.StartDHCP,
 				}
 				service.Channel <- msg
 			},
@@ -255,30 +255,30 @@
 		},
 		fsm.Callbacks{
 			"igmp_join_start": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPMembershipReportV2,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPMembershipReportV2,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
 				service.Channel <- msg
 			},
 			"igmp_leave": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPLeaveGroup,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPLeaveGroup,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
 				service.Channel <- msg
 			},
 			"igmp_join_startv3": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPMembershipReportV3,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPMembershipReportV3,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
@@ -411,7 +411,7 @@
 	}()
 	for msg := range s.Channel {
 		switch msg.Type {
-		case StartEAPOL:
+		case bbsimTypes.StartEAPOL:
 			if err := s.handleEapolStart(s.Stream); err != nil {
 				serviceLogger.WithFields(log.Fields{
 					"OnuId":  s.Onu.ID,
@@ -422,7 +422,7 @@
 				}).Error("Error while sending EapolStart packet")
 				_ = s.EapolState.Event("auth_failed")
 			}
-		case StartDHCP:
+		case bbsimTypes.StartDHCP:
 			if err := s.handleDHCPStart(s.Stream); err != nil {
 				serviceLogger.WithFields(log.Fields{
 					"OnuId":  s.Onu.ID,
@@ -434,8 +434,8 @@
 				_ = s.DHCPState.Event("dhcp_failed")
 
 			}
-		case IGMPMembershipReportV2:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPMembershipReportV2:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,
@@ -443,8 +443,8 @@
 				"Name":   s.Name,
 			}).Debug("Received IGMPMembershipReportV2 message on ONU channel")
 			_ = igmp.SendIGMPMembershipReportV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
-		case IGMPLeaveGroup:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPLeaveGroup:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,
@@ -452,8 +452,8 @@
 				"Name":   s.Name,
 			}).Debug("Received IGMPLeaveGroupV2 message on ONU channel")
 			_ = igmp.SendIGMPLeaveGroupV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
-		case IGMPMembershipReportV3:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPMembershipReportV3:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,