[VOL-4962] openonuAdapterGo - indication of compatibility issues of ONU during configuration

Change-Id: I02ff2d2fc122e6fb423334ceb935be6d57b51828
diff --git a/VERSION b/VERSION
index 5d9ade1..10c2c0c 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.9.2
+2.10.0
diff --git a/internal/pkg/avcfg/omci_ani_config.go b/internal/pkg/avcfg/omci_ani_config.go
index 77ebb75..3e7be63 100755
--- a/internal/pkg/avcfg/omci_ani_config.go
+++ b/internal/pkg/avcfg/omci_ani_config.go
@@ -1265,7 +1265,9 @@
 	} else {
 		logger.Errorw(ctx, "Omci CreateResponse Error - later: drive FSM to abort state ?",
 			log.Fields{"Error": msgObj.Result, "device-id": oFsm.deviceID})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		// possibly force FSM into abort or ignore some errors for some messages?
+		oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return
 	}
 }
@@ -1313,8 +1315,9 @@
 	if msgObj.Result != me.Success {
 		logger.Errorw(ctx, "UniPonAniConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?",
 			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
-
+		// possibly force FSM into abort or ignore some errors for some messages?
+		oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		oFsm.handleOmciAniConfigSetFailResponseMessage(ctx, msgObj)
 		return
 	}
@@ -1380,7 +1383,8 @@
 		logger.Errorw(ctx, "UniPonAniConfigFsm - Omci DeleteResponse Error",
 			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 		//TODO:  - later: possibly force FSM into abort or ignore some errors for some messages?
-		//         store error for mgmt display?
+		oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return
 	}
 	oFsm.mutexPLastTxMeInstance.RLock()
@@ -1807,6 +1811,12 @@
 		oFsm.mutexIsAwaitingResponse.Lock()
 		oFsm.isAwaitingResponse = false
 		oFsm.mutexIsAwaitingResponse.Unlock()
+		oFsm.mutexPLastTxMeInstance.RLock()
+		if oFsm.pLastTxMeInstance != nil {
+			oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureTimeout, oFsm.pLastTxMeInstance.GetClassID(),
+				oFsm.pLastTxMeInstance.GetEntityID(), oFsm.pLastTxMeInstance.GetClassID().String(), 0)
+		}
+		oFsm.mutexPLastTxMeInstance.RUnlock()
 		return fmt.Errorf("uniPonAniConfigFsm multi entity timeout %s", oFsm.deviceID)
 	case success := <-oFsm.omciMIdsResponseReceived:
 		if success {
diff --git a/internal/pkg/avcfg/omci_vlan_config.go b/internal/pkg/avcfg/omci_vlan_config.go
index 394602b..b17de4d 100755
--- a/internal/pkg/avcfg/omci_vlan_config.go
+++ b/internal/pkg/avcfg/omci_vlan_config.go
@@ -2003,7 +2003,9 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "UniVlanConfigFsm Omci SetResponse Error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+				// possibly force FSM into abort or ignore some errors for some messages?
+				oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+					msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 				return
 			}
 			oFsm.mutexPLastTxMeInstance.RLock()
@@ -2065,7 +2067,9 @@
 	if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
 		logger.Errorw(ctx, "Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": oFsm.deviceID,
 			"Error": msgObj.Result})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		// possibly force FSM into abort or ignore some errors for some messages?
+		oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return fmt.Errorf("omci CreateResponse Error for device-id %x",
 			oFsm.deviceID)
 	}
@@ -2121,7 +2125,9 @@
 	if msgObj.Result != me.Success {
 		logger.Errorw(ctx, "UniVlanConfigFsm - Omci DeleteResponse Error - later: drive FSM to abort state ?",
 			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		// possibly force FSM into abort or ignore some errors for some messages?
+		oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return fmt.Errorf("omci DeleteResponse Error for device-id %x",
 			oFsm.deviceID)
 	}
@@ -2868,6 +2874,12 @@
 		oFsm.mutexIsAwaitingResponse.Lock()
 		oFsm.isAwaitingResponse = false
 		oFsm.mutexIsAwaitingResponse.Unlock()
+		oFsm.mutexPLastTxMeInstance.RLock()
+		if oFsm.pLastTxMeInstance != nil {
+			oFsm.pOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureTimeout, oFsm.pLastTxMeInstance.GetClassID(),
+				oFsm.pLastTxMeInstance.GetEntityID(), oFsm.pLastTxMeInstance.GetClassID().String(), 0)
+		}
+		oFsm.mutexPLastTxMeInstance.RUnlock()
 		return fmt.Errorf("uniVlanConfigFsm multi entity timeout %s", oFsm.deviceID)
 	case success := <-oFsm.omciMIdsResponseReceived:
 		if success {
diff --git a/internal/pkg/common/defines.go b/internal/pkg/common/defines.go
index ae705e3..b9c9f17 100755
--- a/internal/pkg/common/defines.go
+++ b/internal/pkg/common/defines.go
@@ -364,6 +364,12 @@
 	OnuOmciCommunicationFailureSwUpgrade     = "ONU_OMCI_COMMUNICATION_FAILURE_SW_UPGRADE"
 	OnuOmciCommunicationFailureSwUpgradeDesc = "OMCI communication during ONU SW upgrade failed"
 
+	OnuConfigFailureResponseErr     = "ONU_CONFIG_FAILURE_RESPONSE_ERROR"
+	OnuConfigFailureResponseErrDesc = "ONU config failed - response error: "
+
+	OnuConfigFailureTimeout     = "ONU_CONFIG_FAILURE_TIMEOUT"
+	OnuConfigFailureTimeoutDesc = "ONU config failed - timeout, OMCI ME: "
+
 	OnuConfigFailureMissingTcont     = "ONU_CONFIG_FAILURE_MISSING_TCONT"
 	OnuConfigFailureMissingTcontDesc = "ONU config failed - no further TCONT resources available at ONU"
 
diff --git a/internal/pkg/common/omci_cc.go b/internal/pkg/common/omci_cc.go
index 25f34de..6cb15b7 100755
--- a/internal/pkg/common/omci_cc.go
+++ b/internal/pkg/common/omci_cc.go
@@ -117,6 +117,8 @@
 	coreClient         *vgrpc.Client
 	supportExtMsg      bool
 	rxOmciFrameError   tOmciReceiveError
+	confFailMEs        []me.ClassID
+	mutexConfFailMEs   sync.RWMutex
 
 	mutexCounters sync.RWMutex
 	countersBase  txRxCounters
@@ -168,6 +170,7 @@
 	omciCC.coreClient = coreClient
 	omciCC.supportExtMsg = false
 	omciCC.rxOmciFrameError = cOmciMessageReceiveNoError
+	omciCC.confFailMEs = nil
 	omciCC.countersBase = txRxCounters{0, 0, 0, 0}
 	omciCC.countersExt = txRxCounters{0, 0, 0, 0}
 	omciCC.txRetries = 0
@@ -213,6 +216,7 @@
 	oo.UploadSequNo = 0
 	oo.UploadNoOfCmds = 0
 	oo.rxOmciFrameError = cOmciMessageReceiveNoError
+	oo.ResetConfFailMEs()
 
 	//reset the stats counter
 	oo.mutexCounters.Lock()
@@ -5243,3 +5247,48 @@
 	defer oo.mutexCounters.Unlock()
 	oo.txTimeouts++
 }
+
+// NotifyAboutOnuConfigFailure - trigger ONU DeviceEvent to notify about ONU config failure
+func (oo *OmciCC) NotifyAboutOnuConfigFailure(ctx context.Context, errID string, meClassID me.ClassID, meEntityID uint16,
+	meName string, meResult me.Results) {
+	var description string
+	if !oo.confFailMeAlreadyHandled(meClassID) {
+		switch errID {
+		case OnuConfigFailureResponseErr:
+			description = OnuConfigFailureResponseErrDesc + meResult.String() +
+				", OMCI ME: " + meName + " / instance: " + fmt.Sprintf("%d", meEntityID) + " (only first instance reported)"
+		case OnuConfigFailureTimeout:
+			description = OnuConfigFailureTimeoutDesc + meName + " / instance: " + fmt.Sprintf("%d", meEntityID) +
+				" (only first instance reported)"
+		default:
+			logger.Warnw(ctx, "method called with undefined errID", log.Fields{"errID": errID, "device-id": oo.deviceID})
+			return
+		}
+		oo.pOnuDeviceEntry.SendOnuDeviceEvent(ctx, errID, description)
+		oo.appendConfFailMe(meClassID)
+	}
+}
+
+func (oo *OmciCC) confFailMeAlreadyHandled(meClassID me.ClassID) bool {
+	oo.mutexConfFailMEs.RLock()
+	defer oo.mutexConfFailMEs.RUnlock()
+	for _, v := range oo.confFailMEs {
+		if v == meClassID {
+			return true
+		}
+	}
+	return false
+}
+
+func (oo *OmciCC) appendConfFailMe(meClassID me.ClassID) {
+	oo.mutexConfFailMEs.Lock()
+	defer oo.mutexConfFailMEs.Unlock()
+	oo.confFailMEs = append(oo.confFailMEs, meClassID)
+}
+
+// ResetConfFailMEs - reset list of stored config failure MEs
+func (oo *OmciCC) ResetConfFailMEs() {
+	oo.mutexConfFailMEs.Lock()
+	defer oo.mutexConfFailMEs.Unlock()
+	oo.confFailMEs = nil
+}
diff --git a/internal/pkg/mib/mib_download.go b/internal/pkg/mib/mib_download.go
index 32c025c..167cb44 100755
--- a/internal/pkg/mib/mib_download.go
+++ b/internal/pkg/mib/mib_download.go
@@ -182,7 +182,9 @@
 	logger.Debugw(ctx, "CreateResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
 	if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
 		logger.Errorw(ctx, "Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID, "Error": msgObj.Result})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		// possibly force FSM into abort or ignore some errors for some messages?
+		onuDeviceEntry.PDevOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return
 	}
 	// maybe there is a way of pushing the specific create response type generally to the FSM
@@ -245,7 +247,9 @@
 	if msgObj.Result != me.Success {
 		logger.Errorw(ctx, "Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID,
 			"Error": msgObj.Result})
-		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		// possibly force FSM into abort or ignore some errors for some messages?
+		onuDeviceEntry.PDevOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureResponseErr, msgObj.EntityClass,
+			msgObj.EntityInstance, msgObj.EntityClass.String(), msgObj.Result)
 		return
 	}
 	// compare comments above for CreateResponse (apply also here ...)
@@ -384,6 +388,13 @@
 	// case <-ctx.Done():
 	// 		logger.Info("MibDownload-bridge-init message reception canceled", log.Fields{"for device-id": onuDeviceEntry.deviceID})
 	case <-time.After(onuDeviceEntry.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
+		onuDeviceEntry.mutexPLastTxMeInstance.RLock()
+		if onuDeviceEntry.pLastTxMeInstance != nil {
+			onuDeviceEntry.PDevOmciCC.NotifyAboutOnuConfigFailure(ctx, cmn.OnuConfigFailureTimeout,
+				onuDeviceEntry.pLastTxMeInstance.GetClassID(), onuDeviceEntry.pLastTxMeInstance.GetEntityID(),
+				onuDeviceEntry.pLastTxMeInstance.GetClassID().String(), 0)
+		}
+		onuDeviceEntry.mutexPLastTxMeInstance.RUnlock()
 		logger.Warnw(ctx, "MibDownload-bridge-init timeout", log.Fields{"for device-id": onuDeviceEntry.deviceID})
 		return fmt.Errorf("mibDownloadBridgeInit timeout %s", onuDeviceEntry.deviceID)
 	case success := <-onuDeviceEntry.omciMessageReceived:
diff --git a/internal/pkg/mib/mib_sync.go b/internal/pkg/mib/mib_sync.go
index bbc2c8e..155a83e 100755
--- a/internal/pkg/mib/mib_sync.go
+++ b/internal/pkg/mib/mib_sync.go
@@ -588,6 +588,7 @@
 					oo.MutexPersOnuConfig.Lock()
 					oo.SOnuPersistentData.PersMibDataSyncAdpt = cmn.MdsDefaultMib
 					oo.MutexPersOnuConfig.Unlock()
+					oo.PDevOmciCC.ResetConfFailMEs()
 					// trigger retrieval of VendorId and SerialNumber
 					_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetVendorAndSerial)
 					return
diff --git a/internal/pkg/mib/onu_device_entry.go b/internal/pkg/mib/onu_device_entry.go
index 83de39f..35e6357 100755
--- a/internal/pkg/mib/onu_device_entry.go
+++ b/internal/pkg/mib/onu_device_entry.go
@@ -1057,5 +1057,6 @@
 		Description:     aDescription,
 		Context:         context,
 	}
+	logger.Debugw(ctx, "send device event", log.Fields{"deviceEvent": deviceEvent, "device-id": oo.deviceID})
 	_ = oo.eventProxy.SendDeviceEvent(ctx, deviceEvent, voltha.EventCategory_COMMUNICATION, voltha.EventSubCategory_ONU, time.Now().Unix())
 }