VOL-3730
* When the OLT connectState is unreachable, raise OLT Communication Failure alarm (publish raise-alarm to kafka)
* When the OLT state is up, clear OLT Comunication Failure alarm (publish clear-alarm to kafka)

Change-Id: Ief3d48e359490e6638842042347029e2cbdd17aa
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 413e490..2e04e21 100644
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -604,6 +604,13 @@
 		voltha.OperStatus_ACTIVE); err != nil {
 		return olterrors.NewErrAdapter("device-update-failed", log.Fields{"device-id": dh.device.Id}, err)
 	}
+
+	//Clear olt communication failure event
+	dh.device.ConnectStatus = voltha.ConnectStatus_REACHABLE
+	dh.device.OperStatus = voltha.OperStatus_ACTIVE
+	raisedTs := time.Now().UnixNano()
+	go dh.eventMgr.oltCommunicationEvent(ctx, dh.device, raisedTs)
+
 	return nil
 }
 
@@ -1959,6 +1966,13 @@
 		if err = dh.coreProxy.PortsStateUpdate(ctx, dh.device.Id, 0, voltha.OperStatus_UNKNOWN); err != nil {
 			_ = olterrors.NewErrAdapter("port-update-failed", log.Fields{"device-id": dh.device.Id}, err).Log()
 		}
+
+		//raise olt communication failure event
+		raisedTs := time.Now().UnixNano()
+		device.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
+		device.OperStatus = voltha.OperStatus_UNKNOWN
+		go dh.eventMgr.oltCommunicationEvent(ctx, device, raisedTs)
+
 		go dh.cleanupDeviceResources(ctx)
 
 		dh.lockDevice.RLock()
diff --git a/internal/pkg/core/openolt_eventmgr.go b/internal/pkg/core/openolt_eventmgr.go
index 65b76e6..6908541 100644
--- a/internal/pkg/core/openolt_eventmgr.go
+++ b/internal/pkg/core/openolt_eventmgr.go
@@ -38,6 +38,7 @@
 	onuLopcMissEvent                    = "ONU_LOPC_MISS"
 	onuLopcMicErrorEvent                = "ONU_LOPC_MIC_ERROR"
 	oltLosEvent                         = "OLT_LOSS_OF_SIGNAL"
+	oltCommFailure                      = "OLT_COMMUNICATION_FAILURE"
 	oltIndicationDown                   = "OLT_DOWN_INDICATION"
 	onuDyingGaspEvent                   = "ONU_DYING_GASP"
 	onuSignalsFailEvent                 = "ONU_SIGNALS_FAIL"
@@ -72,8 +73,30 @@
 )
 
 const (
+	// ContextOltAdminState is for the admin state of the Olt in the context of the event
+	ContextOltAdminState = "admin-state"
+	// ContextOltConnectState is for the connect state of the Olt in the context of the event
+	ContextOltConnectState = "connect-state"
 	// ContextOltOperState is for the operational state of the Olt in the context of the event
 	ContextOltOperState = "oper-state"
+	// ContextOltVendor is for the Olt vendor in the context of the event
+	ContextOltVendor = "vendor"
+	// ContextOltType is for the Olt type in the context of the event
+	ContextOltType = "type"
+	// ContextOltParentID is for the Olt parent id in the context of the event
+	ContextOltParentID = "parent-id"
+	// ContextOltParentPortNo is for the Olt parent port no in the context of the event
+	ContextOltParentPortNo = "parent-port-no"
+	// ContextOltFirmwareVersion is for the Olt firmware version in the context of the event
+	ContextOltFirmwareVersion = "firmware-version"
+	// ContextOltHardwareVersion is for the Olt hardware version in the context of the event
+	ContextOltHardwareVersion = "hardware-version"
+	// ContextOltSerialNumber is for the serial number of the OLT
+	ContextOltSerialNumber = "serial-number"
+	// ContextOltMacAddress is for the OLT mac address
+	ContextOltMacAddress = "mac-address"
+	// ContextDeviceID is for the device id in the context of the event
+	ContextDeviceID = "id"
 	// ContextOnuOnuID is for the Onu Id in the context of the event
 	ContextOnuOnuID = "onu-id"
 	// ContextOnuPonIntfID is for the PON interface Id on which the Onu Event occurred
@@ -177,6 +200,44 @@
 	}
 }
 
+func (em *OpenOltEventMgr) oltCommunicationEvent(ctx context.Context, device *voltha.Device, raisedTs int64) {
+	if device == nil {
+		logger.Warn(ctx, "device-is-nil-can't-send-olt-communication-failure-event")
+		return
+	}
+	var de voltha.DeviceEvent
+	context := make(map[string]string)
+	context[ContextOltOperState] = device.OperStatus.String()
+	context[ContextOltAdminState] = device.AdminState.String()
+	context[ContextOltVendor] = device.Vendor
+	context[ContextOltConnectState] = device.ConnectStatus.String()
+	context[ContextOltType] = device.Type
+	context[ContextOltParentID] = device.ParentId
+	context[ContextOltParentPortNo] = fmt.Sprintf("%d", device.ParentPortNo)
+	context[ContextDeviceID] = device.Id
+	context[ContextOltFirmwareVersion] = device.FirmwareVersion
+	context[ContextOltHardwareVersion] = device.HardwareVersion
+	context[ContextOltSerialNumber] = device.SerialNumber
+	context[ContextOltMacAddress] = device.MacAddress
+	de.Context = context
+	de.ResourceId = device.Id
+
+	if device.ConnectStatus == voltha.ConnectStatus_UNREACHABLE {
+		de.DeviceEventName = fmt.Sprintf("%s_%s", oltCommFailure, "RAISE_EVENT")
+	} else {
+		de.DeviceEventName = fmt.Sprintf("%s_%s", oltCommFailure, "CLEAR_EVENT")
+	}
+
+	if err := em.eventProxy.SendDeviceEvent(ctx, &de, voltha.EventCategory_COMMUNICATION, voltha.EventSubCategory_OLT, raisedTs); err != nil {
+		logger.Errorw(ctx, "failed-to-send-olt-comm-failure-event", log.Fields{"err": err})
+	}
+	logger.Debugw(ctx, "olt-comm-failure-event-sent-to-kafka",
+		log.Fields{
+			"device-id":      device.Id,
+			"connect-status": device.ConnectStatus,
+		})
+}
+
 // oltUpDownIndication handles Up and Down state of an OLT
 func (em *OpenOltEventMgr) oltUpDownIndication(ctx context.Context, oltIndication *oop.OltIndication, deviceID string, raisedTs int64) error {
 	var de voltha.DeviceEvent