[VOL-3330] removal of tech profile OMCI related configuration on tech profile deletion - version 0.1.15-dev144

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: Ife9ddc140e725af1375d4a786e2b5079edbb8f33
diff --git a/VERSION b/VERSION
index 71d6a66..19b8c33 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.14
+0.1.15-dev144
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index fbb324e..e2b847d 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -394,7 +394,7 @@
 
 	var wg sync.WaitGroup
 	wg.Add(1) // for the 1 go routine to finish
-	go dh.pOnuTP.deleteTpResource(dctx, uniID, delGemPortMsg.TpPath,
+	go dh.pOnuTP.deleteTpResource(dctx, uniID, tpID, delGemPortMsg.TpPath,
 		cResourceGemPort, delGemPortMsg.GemPortId, &wg)
 	dh.waitForCompletion(cancel, &wg, "GemDelete") //wait for background process to finish
 
@@ -454,7 +454,7 @@
 
 		var wg sync.WaitGroup
 		wg.Add(2) // for the 2 go routines to finish
-		go dh.pOnuTP.deleteTpResource(dctx, uniID, delTcontMsg.TpPath,
+		go dh.pOnuTP.deleteTpResource(dctx, uniID, tpID, delTcontMsg.TpPath,
 			cResourceTcont, delTcontMsg.AllocId, &wg)
 		// Removal of the tcont/alloc id mapping represents the removal of the tech profile
 		go pDevEntry.updateOnuKvStore(dctx, &wg)
@@ -845,6 +845,10 @@
 		return err
 	}
 	dh.ReadyForSpecificOmciConfig = false
+	//no specific activity to synchronize any internal FSM to the 'rebooted' state is explicitly done here
+	//  the expectation ids for a real device, that it will be synced with the expected following 'down' indication
+	//  as BBSIM does not support this testing requires explicite disable/enable device calls in which sequence also
+	//  all other FSM's should be synchronized again
 	return nil
 }
 
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index 7341ff6..0f44d84 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -35,19 +35,26 @@
 
 const (
 	// events of config PON ANI port FSM
-	aniEvStart           = "uniEvStart"
-	aniEvStartConfig     = "aniEvStartConfig"
-	aniEvRxDot1pmapCResp = "aniEvRxDot1pmapCResp"
-	aniEvRxMbpcdResp     = "aniEvRxMbpcdResp"
-	aniEvRxTcontsResp    = "aniEvRxTcontsResp"
-	aniEvRxGemntcpsResp  = "aniEvRxGemntcpsResp"
-	aniEvRxGemiwsResp    = "aniEvRxGemiwsResp"
-	aniEvRxPrioqsResp    = "aniEvRxPrioqsResp"
-	aniEvRxDot1pmapSResp = "aniEvRxDot1pmapSResp"
-	aniEvTimeoutSimple   = "aniEvTimeoutSimple"
-	aniEvTimeoutMids     = "aniEvTimeoutMids"
-	aniEvReset           = "aniEvReset"
-	aniEvRestart         = "aniEvRestart"
+	aniEvStart             = "aniEvStart"
+	aniEvStartConfig       = "aniEvStartConfig"
+	aniEvRxDot1pmapCResp   = "aniEvRxDot1pmapCResp"
+	aniEvRxMbpcdResp       = "aniEvRxMbpcdResp"
+	aniEvRxTcontsResp      = "aniEvRxTcontsResp"
+	aniEvRxGemntcpsResp    = "aniEvRxGemntcpsResp"
+	aniEvRxGemiwsResp      = "aniEvRxGemiwsResp"
+	aniEvRxPrioqsResp      = "aniEvRxPrioqsResp"
+	aniEvRxDot1pmapSResp   = "aniEvRxDot1pmapSResp"
+	aniEvRemGemiw          = "aniEvRemGemiw"
+	aniEvRxRemGemiwResp    = "aniEvRxRemGemiwResp"
+	aniEvRxRemGemntpResp   = "aniEvRxRemGemntpResp"
+	aniEvRemTcontPath      = "aniEvRemTcontPath"
+	aniEvRxResetTcontResp  = "aniEvRxResetTcontResp"
+	aniEvRxRem1pMapperResp = "aniEvRxRem1pMapperResp"
+	aniEvRxRemAniBPCDResp  = "aniEvRxRemAniBPCDResp"
+	aniEvTimeoutSimple     = "aniEvTimeoutSimple"
+	aniEvTimeoutMids       = "aniEvTimeoutMids"
+	aniEvReset             = "aniEvReset"
+	aniEvRestart           = "aniEvRestart"
 )
 const (
 	// states of config PON ANI port FSM
@@ -61,6 +68,12 @@
 	aniStSettingPQs          = "aniStSettingPQs"
 	aniStSettingDot1PMapper  = "aniStSettingDot1PMapper"
 	aniStConfigDone          = "aniStConfigDone"
+	aniStRemovingGemIW       = "aniStRemovingGemIW"
+	aniStRemovingGemNCTP     = "aniStRemovingGemNCTP"
+	aniStResetTcont          = "aniStResetTcont"
+	aniStRemDot1PMapper      = "aniStRemDot1PMapper"
+	aniStRemAniBPCD          = "aniStRemAniBPCD"
+	aniStRemoveDone          = "aniStRemoveDone"
 	aniStResetting           = "aniStResetting"
 )
 
@@ -87,6 +100,7 @@
 	pUniTechProf             *onuUniTechProf
 	pOnuDB                   *onuDeviceDB
 	techProfileID            uint8
+	uniTpKey                 uniTP
 	requestEvent             OnuDeviceEvent
 	omciMIdsResponseReceived chan bool //separate channel needed for checking multiInstance OMCI message responses
 	pAdaptFsm                *AdapterFsm
@@ -99,6 +113,7 @@
 	alloc0ID                 uint16
 	gemPortAttribsSlice      []ponAniGemPortAttribs
 	pLastTxMeInstance        *me.ManagedEntity
+	requestEventOffset       uint8 //used to indicate ConfigDone or Removed using successor (enum)
 }
 
 //newUniPonAniConfigFsm is the 'constructor' for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
@@ -116,6 +131,8 @@
 		requestEvent:   aRequestEvent,
 		chanSet:        false,
 	}
+	instFsm.uniTpKey = uniTP{uniID: apUniPort.uniID, tpID: aTechProfileID}
+
 	instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
 	if instFsm.pAdaptFsm == nil {
 		logger.Errorw("uniPonAniConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
@@ -142,15 +159,28 @@
 			{Name: aniEvRxPrioqsResp, Src: []string{aniStSettingPQs}, Dst: aniStSettingDot1PMapper},
 			{Name: aniEvRxDot1pmapSResp, Src: []string{aniStSettingDot1PMapper}, Dst: aniStConfigDone},
 
-			{Name: aniEvTimeoutSimple, Src: []string{
-				aniStCreatingDot1PMapper, aniStCreatingMBPCD, aniStSettingTconts, aniStSettingDot1PMapper}, Dst: aniStStarting},
+			//for removing Gem related resources
+			{Name: aniEvRemGemiw, Src: []string{aniStConfigDone}, Dst: aniStRemovingGemIW},
+			{Name: aniEvRxRemGemiwResp, Src: []string{aniStRemovingGemIW}, Dst: aniStRemovingGemNCTP},
+			{Name: aniEvRxRemGemntpResp, Src: []string{aniStRemovingGemNCTP}, Dst: aniStConfigDone},
+
+			//for removing TCONT related resources
+			{Name: aniEvRemTcontPath, Src: []string{aniStConfigDone}, Dst: aniStResetTcont},
+			{Name: aniEvRxResetTcontResp, Src: []string{aniStResetTcont}, Dst: aniStRemDot1PMapper},
+			{Name: aniEvRxRem1pMapperResp, Src: []string{aniStRemDot1PMapper}, Dst: aniStRemAniBPCD},
+			{Name: aniEvRxRemAniBPCDResp, Src: []string{aniStRemAniBPCD}, Dst: aniStRemoveDone},
+
+			{Name: aniEvTimeoutSimple, Src: []string{aniStCreatingDot1PMapper, aniStCreatingMBPCD, aniStSettingTconts, aniStSettingDot1PMapper,
+				aniStRemovingGemIW, aniStRemovingGemNCTP,
+				aniStResetTcont, aniStRemDot1PMapper, aniStRemAniBPCD, aniStRemoveDone}, Dst: aniStStarting},
 			{Name: aniEvTimeoutMids, Src: []string{
 				aniStCreatingGemNCTPs, aniStCreatingGemIWs, aniStSettingPQs}, Dst: aniStStarting},
 
 			// exceptional treatment for all states except aniStResetting
 			{Name: aniEvReset, Src: []string{aniStStarting, aniStCreatingDot1PMapper, aniStCreatingMBPCD,
 				aniStSettingTconts, aniStCreatingGemNCTPs, aniStCreatingGemIWs, aniStSettingPQs, aniStSettingDot1PMapper,
-				aniStConfigDone}, Dst: aniStResetting},
+				aniStConfigDone, aniStRemovingGemIW, aniStRemovingGemNCTP,
+				aniStResetTcont, aniStRemDot1PMapper, aniStRemAniBPCD, aniStRemoveDone}, Dst: aniStResetting},
 			// the only way to get to resource-cleared disabled state again is via "resseting"
 			{Name: aniEvRestart, Src: []string{aniStResetting}, Dst: aniStDisabled},
 		},
@@ -166,6 +196,12 @@
 			("enter_" + aniStSettingPQs):          func(e *fsm.Event) { instFsm.enterSettingPQs(e) },
 			("enter_" + aniStSettingDot1PMapper):  func(e *fsm.Event) { instFsm.enterSettingDot1PMapper(e) },
 			("enter_" + aniStConfigDone):          func(e *fsm.Event) { instFsm.enterAniConfigDone(e) },
+			("enter_" + aniStRemovingGemIW):       func(e *fsm.Event) { instFsm.enterRemovingGemIW(e) },
+			("enter_" + aniStRemovingGemNCTP):     func(e *fsm.Event) { instFsm.enterRemovingGemNCTP(e) },
+			("enter_" + aniStResetTcont):          func(e *fsm.Event) { instFsm.enterResettingTcont(e) },
+			("enter_" + aniStRemDot1PMapper):      func(e *fsm.Event) { instFsm.enterRemoving1pMapper(e) },
+			("enter_" + aniStRemAniBPCD):          func(e *fsm.Event) { instFsm.enterRemovingAniBPCD(e) },
+			("enter_" + aniStRemoveDone):          func(e *fsm.Event) { instFsm.enterAniRemoveDone(e) },
 			("enter_" + aniStResetting):           func(e *fsm.Event) { instFsm.enterResettingState(e) },
 			("enter_" + aniStDisabled):            func(e *fsm.Event) { instFsm.enterDisabledState(e) },
 		},
@@ -189,7 +225,6 @@
 
 func (oFsm *uniPonAniConfigFsm) prepareAndEnterConfigState(aPAFsm *AdapterFsm) {
 	if aPAFsm != nil && aPAFsm.pFsm != nil {
-		uniTpKey := uniTP{uniID: oFsm.pOnuUniPort.uniID, tpID: oFsm.techProfileID}
 		//stick to pythonAdapter numbering scheme
 		//index 0 in naming refers to possible usage of multiple instances (later)
 		oFsm.mapperSP0ID = ieeeMapperServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) + uint16(oFsm.techProfileID)
@@ -262,8 +297,8 @@
 
 		// Access critical state with lock
 		oFsm.pUniTechProf.mutexTPState.Lock()
-		oFsm.alloc0ID = oFsm.pUniTechProf.mapPonAniConfig[uniTpKey].tcontParams.allocID
-		mapGemPortParams := oFsm.pUniTechProf.mapPonAniConfig[uniTpKey].mapGemPortParams
+		oFsm.alloc0ID = oFsm.pUniTechProf.mapPonAniConfig[oFsm.uniTpKey].tcontParams.allocID
+		mapGemPortParams := oFsm.pUniTechProf.mapPonAniConfig[oFsm.uniTpKey].mapGemPortParams
 		oFsm.pUniTechProf.mutexTPState.Unlock()
 
 		loGemPortAttribs := ponAniGemPortAttribs{}
@@ -342,8 +377,8 @@
 }
 
 func (oFsm *uniPonAniConfigFsm) enterConfigStartingState(e *fsm.Event) {
-	logger.Debugw("UniPonAniConfigFsm start", log.Fields{"in state": e.FSM.Current(),
-		"device-id": oFsm.deviceID})
+	logger.Debugw("UniPonAniConfigFsm start", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	// in case the used channel is not yet defined (can be re-used after restarts)
 	if oFsm.omciMIdsResponseReceived == nil {
 		oFsm.omciMIdsResponseReceived = make(chan bool)
@@ -374,7 +409,8 @@
 func (oFsm *uniPonAniConfigFsm) enterCreatingDot1PMapper(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Create::Dot1PMapper", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
+	oFsm.requestEventOffset = 0 //0 offset for last config request activity
 	meInstance := oFsm.pOmciCC.sendCreateDot1PMapper(context.TODO(), ConstDefaultOmciTimeout, true,
 		oFsm.mapperSP0ID, oFsm.pAdaptFsm.commChan)
 	//accept also nil as (error) return value for writing to LastTx
@@ -386,7 +422,7 @@
 	logger.Debugw("uniPonAniConfigFsm Tx Create::MBPCD", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
 		"TPPtr":     strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	bridgePtr := macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) //cmp also omci_cc.go::sendCreateMBServiceProfile
 	meParams := me.ParamData{
 		EntityID: oFsm.macBPCD0ID,
@@ -402,14 +438,13 @@
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
 	oFsm.pLastTxMeInstance = meInstance
-
 }
 
 func (oFsm *uniPonAniConfigFsm) enterSettingTconts(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Set::Tcont", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
 		"AllocId":   strconv.FormatInt(int64(oFsm.alloc0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	meParams := me.ParamData{
 		EntityID: oFsm.tcont0ID,
 		Attributes: me.AttributeValueMap{
@@ -425,13 +460,13 @@
 
 func (oFsm *uniPonAniConfigFsm) enterCreatingGemNCTPs(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm - start creating GemNWCtp loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	go oFsm.performCreatingGemNCTPs()
 }
 
 func (oFsm *uniPonAniConfigFsm) enterCreatingGemIWs(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm - start creating GemIwTP loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	go oFsm.performCreatingGemIWs()
 }
 
@@ -443,7 +478,8 @@
 
 func (oFsm *uniPonAniConfigFsm) enterSettingDot1PMapper(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Set::.1pMapper with all PBits set", log.Fields{"EntitytId": 0x8042, /*cmp above*/
-		"toGemIw": 1024 /* cmp above */, "in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+		"toGemIw":   1024, /* cmp above */
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 
 	logger.Debugw("uniPonAniConfigFsm Tx Set::1pMapper", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
@@ -513,14 +549,17 @@
 }
 
 func (oFsm *uniPonAniConfigFsm) enterAniConfigDone(e *fsm.Event) {
-	logger.Debugw("uniPonAniConfigFsm send dh event notification recheck pending flow config", log.Fields{
-		"from_State": e.FSM.Current(), "device-id": oFsm.deviceID})
+	logger.Debugw("uniPonAniConfigFsm ani config done", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	//use DeviceHandler event notification directly
-	oFsm.pDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
+	oFsm.pDeviceHandler.deviceProcStatusUpdate(OnuDeviceEvent((uint8(oFsm.requestEvent) + oFsm.requestEventOffset)))
 	//store that the UNI related techProfile processing is done for the given Profile and Uni
 	oFsm.pUniTechProf.setConfigDone(oFsm.pOnuUniPort.uniID, oFsm.techProfileID, true)
 	//if techProfile processing is done it must be checked, if some prior/parallel flow configuration is pending
-	go oFsm.pDeviceHandler.verifyUniVlanConfigRequest(oFsm.pOnuUniPort)
+	//  but only in case the techProfile was configured (not deleted)
+	if oFsm.requestEventOffset == 0 {
+		go oFsm.pDeviceHandler.verifyUniVlanConfigRequest(oFsm.pOnuUniPort)
+	}
 
 	if oFsm.chanSet {
 		// indicate processing done to the caller
@@ -533,8 +572,98 @@
 	//the FSM is left active in this state as long as no specific reset or remove is requested from outside
 }
 
+func (oFsm *uniPonAniConfigFsm) enterRemovingGemIW(e *fsm.Event) {
+	// get the related GemPort entity Id from pUniTechProf, OMCI Gem* entityID is set to be equal to GemPortId!
+	oFsm.pUniTechProf.mutexTPState.Lock()
+	loGemPortID := (*(oFsm.pUniTechProf.mapRemoveGemEntry[oFsm.uniTpKey])).gemPortID
+	oFsm.pUniTechProf.mutexTPState.Unlock()
+	logger.Debugw("uniPonAniConfigFsm - start removing one GemIwTP", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID,
+		"GemIwTp-entity-id": loGemPortID})
+	oFsm.requestEventOffset = 1 //offset 1 to indicate last activity = remove
+
+	// this state entry is only expected in a suitable state (checked outside in onu_uni_tp)
+	meInstance := oFsm.pOmciCC.sendDeleteGemIWTP(context.TODO(), ConstDefaultOmciTimeout, true,
+		oFsm.pAdaptFsm.commChan, loGemPortID)
+	oFsm.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *uniPonAniConfigFsm) enterRemovingGemNCTP(e *fsm.Event) {
+	oFsm.pUniTechProf.mutexTPState.Lock()
+	loGemPortID := (*(oFsm.pUniTechProf.mapRemoveGemEntry[oFsm.uniTpKey])).gemPortID
+	oFsm.pUniTechProf.mutexTPState.Unlock()
+	logger.Debugw("uniPonAniConfigFsm - start removing one GemNCTP", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID,
+		"GemNCTP-entity-id": loGemPortID})
+	// this state entry is only expected in a suitable state (checked outside in onu_uni_tp)
+	meInstance := oFsm.pOmciCC.sendDeleteGemNCTP(context.TODO(), ConstDefaultOmciTimeout, true,
+		oFsm.pAdaptFsm.commChan, loGemPortID)
+	oFsm.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *uniPonAniConfigFsm) enterResettingTcont(e *fsm.Event) {
+	logger.Debugw("uniPonAniConfigFsm - start resetting the TCont", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
+
+	oFsm.requestEventOffset = 1 //offset 1 for last remove activity
+	// this state entry is only expected in a suitable state (checked outside in onu_uni_tp)
+	meParams := me.ParamData{
+		EntityID: oFsm.tcont0ID,
+		Attributes: me.AttributeValueMap{
+			"AllocId": unusedTcontAllocID,
+		},
+	}
+	meInstance := oFsm.pOmciCC.sendSetTcontVar(context.TODO(), ConstDefaultOmciTimeout, true,
+		oFsm.pAdaptFsm.commChan, meParams)
+	oFsm.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *uniPonAniConfigFsm) enterRemoving1pMapper(e *fsm.Event) {
+	logger.Debugw("uniPonAniConfigFsm - start deleting the .1pMapper", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
+
+	meInstance := oFsm.pOmciCC.sendDeleteDot1PMapper(context.TODO(), ConstDefaultOmciTimeout, true,
+		oFsm.pAdaptFsm.commChan, oFsm.mapperSP0ID)
+	oFsm.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *uniPonAniConfigFsm) enterRemovingAniBPCD(e *fsm.Event) {
+	logger.Debugw("uniPonAniConfigFsm - start deleting the ANI MBCD", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
+
+	meInstance := oFsm.pOmciCC.sendDeleteMBPConfigData(context.TODO(), ConstDefaultOmciTimeout, true,
+		oFsm.pAdaptFsm.commChan, oFsm.macBPCD0ID)
+	oFsm.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *uniPonAniConfigFsm) enterAniRemoveDone(e *fsm.Event) {
+	logger.Debugw("uniPonAniConfigFsm ani removal done", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
+	//use DeviceHandler event notification directly
+	oFsm.pDeviceHandler.deviceProcStatusUpdate(OnuDeviceEvent((uint8(oFsm.requestEvent) + oFsm.requestEventOffset)))
+	if oFsm.chanSet {
+		// indicate processing done to the caller
+		logger.Debugw("uniPonAniConfigFsm processingDone on channel", log.Fields{
+			"ProcessingStep": oFsm.procStep, "from_State": e.FSM.Current(), "device-id": oFsm.deviceID})
+		oFsm.chSuccess <- oFsm.procStep
+		oFsm.chanSet = false //reset the internal channel state
+	}
+
+	//let's reset the state machine in order to release all resources now
+	pConfigAniStateAFsm := oFsm.pAdaptFsm
+	if pConfigAniStateAFsm != nil {
+		// obviously calling some FSM event here directly does not work - so trying to decouple it ...
+		go func(aPAFsm *AdapterFsm) {
+			if aPAFsm != nil && aPAFsm.pFsm != nil {
+				_ = aPAFsm.pFsm.Event(aniEvReset)
+			}
+		}(pConfigAniStateAFsm)
+	}
+}
+
 func (oFsm *uniPonAniConfigFsm) enterResettingState(e *fsm.Event) {
-	logger.Debugw("uniPonAniConfigFsm resetting", log.Fields{"device-id": oFsm.deviceID})
+	logger.Debugw("uniPonAniConfigFsm resetting", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 
 	pConfigAniStateAFsm := oFsm.pAdaptFsm
 	if pConfigAniStateAFsm != nil {
@@ -557,7 +686,8 @@
 }
 
 func (oFsm *uniPonAniConfigFsm) enterDisabledState(e *fsm.Event) {
-	logger.Debugw("uniPonAniConfigFsm enters disabled state", log.Fields{"device-id": oFsm.deviceID})
+	logger.Debugw("uniPonAniConfigFsm enters disabled state", log.Fields{
+		"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
 	oFsm.pLastTxMeInstance = nil
 
 	//remove all TechProf related internal data to allow for new configuration (e.g. with disable/enable procedure)
@@ -671,7 +801,11 @@
 		switch oFsm.pLastTxMeInstance.GetName() {
 		case "TCont":
 			{ // let the FSM proceed ...
-				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxTcontsResp)
+				if oFsm.requestEventOffset == 0 { //from TCont config request
+					_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxTcontsResp)
+				} else { // from T-Cont reset request
+					_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxResetTcontResp)
+				}
 			}
 		case "PriorityQueue":
 			{ // let the PrioQueue init proceed by stopping the wait function
@@ -685,6 +819,53 @@
 	}
 }
 
+func (oFsm *uniPonAniConfigFsm) handleOmciAniConfigDeleteResponseMessage(msg OmciMessage) {
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
+	if msgLayer == nil {
+		logger.Errorw("UniPonAniConfigFsm - Omci Msg layer could not be detected for DeleteResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return
+	}
+	msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
+	if !msgOk {
+		logger.Errorw("UniPonAniConfigFsm - Omci Msg layer could not be assigned for DeleteResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return
+	}
+	logger.Debugw("UniPonAniConfigFsm DeleteResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		logger.Errorw("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?
+		return
+	}
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+		//remove ME from DB //TODO??? obviously the Python code does not store/remove the config ...
+		// if, then something like: oFsm.pOnuDB.XyyMe(msgObj)
+
+		switch oFsm.pLastTxMeInstance.GetName() {
+		case "GemInterworkingTerminationPoint":
+			{ // let the FSM proceed ...
+				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxRemGemiwResp)
+			}
+		case "GemPortNetworkCtp":
+			{ // let the FSM proceed ...
+				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxRemGemntpResp)
+			}
+		case "Ieee8021PMapperServiceProfile":
+			{ // let the FSM proceed ...
+				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxRem1pMapperResp)
+			}
+		case "MacBridgePortConfigurationData":
+			{ // this is the last event of the T-Cont cleanup procedure, FSM may be reset here
+				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxRemAniBPCDResp)
+			}
+		}
+	}
+}
+
 func (oFsm *uniPonAniConfigFsm) handleOmciAniConfigMessage(msg OmciMessage) {
 	logger.Debugw("Rx OMCI UniPonAniConfigFsm Msg", log.Fields{"device-id": oFsm.deviceID,
 		"msgType": msg.OmciMsg.MessageType})
@@ -700,6 +881,11 @@
 			oFsm.handleOmciAniConfigSetResponseMessage(msg)
 
 		} //SetResponseType
+	case omci.DeleteResponseType:
+		{
+			oFsm.handleOmciAniConfigDeleteResponseMessage(msg)
+
+		} //SetResponseType
 	default:
 		{
 			logger.Errorw("uniPonAniConfigFsm - Rx OMCI unhandled MsgType",
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 32d729e..17e674d 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -59,6 +59,8 @@
 const ieeeMapperServiceProfileEID = uint16(0x8001)
 const macBridgePortAniEID = uint16(0x2102)
 
+const unusedTcontAllocID = uint16(0xFFFF) //common unused AllocId for G.984 and G.987 systems
+
 // ### OMCI related definitions - end
 
 //callbackPairEntry to be used for OMCI send/receive correlation
@@ -142,7 +144,7 @@
 
 //stop stops/resets the omciCC
 func (oo *omciCC) stop(ctx context.Context) error {
-	logger.Debugw("omciCC-stopping", log.Fields{"for device-id": oo.deviceID})
+	logger.Debugw("omciCC-stopping", log.Fields{"device-id": oo.deviceID})
 	//reseting all internal data, which might also be helpful for discarding any lingering tx/rx requests
 	oo.mutexTxQueue.Lock()
 	oo.txQueue.Init() // clear the tx queue
@@ -242,17 +244,17 @@
 
 	packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
 	if packet == nil {
-		logger.Errorw("omci-message could not be decoded", log.Fields{"deviceID": oo.deviceID})
+		logger.Errorw("omci-message could not be decoded", log.Fields{"device-id": oo.deviceID})
 		return fmt.Errorf("could not decode rxMsg as OMCI %s", oo.deviceID)
 	}
 	omciLayer := packet.Layer(omci.LayerTypeOMCI)
 	if omciLayer == nil {
-		logger.Errorw("omci-message could not decode omci layer", log.Fields{"deviceID": oo.deviceID})
+		logger.Errorw("omci-message could not decode omci layer", log.Fields{"device-id": oo.deviceID})
 		return fmt.Errorf("could not decode omci layer %s", oo.deviceID)
 	}
 	omciMsg, ok := omciLayer.(*omci.OMCI)
 	if !ok {
-		logger.Errorw("omci-message could not assign omci layer", log.Fields{"deviceID": oo.deviceID})
+		logger.Errorw("omci-message could not assign omci layer", log.Fields{"device-id": oo.deviceID})
 		return fmt.Errorf("could not assign omci layer %s", oo.deviceID)
 	}
 	logger.Debugw("omci-message-decoded:", log.Fields{"omciMsgType": omciMsg.MessageType,
@@ -265,7 +267,7 @@
 		}
 		logger.Errorw("Unexpected TransCorrId != 0  not accepted for autonomous messages",
 			log.Fields{"msgType": omciMsg.MessageType, "payload": hex.EncodeToString(omciMsg.Payload),
-				"deviceID": oo.deviceID})
+				"device-id": oo.deviceID})
 		return fmt.Errorf("autonomous Omci Message with TranSCorrId != 0 not acccepted %s", oo.deviceID)
 
 	}
@@ -281,7 +283,7 @@
 		oo.mutexRxSchedMap.Unlock()
 	} else {
 		oo.mutexRxSchedMap.Unlock()
-		logger.Errorw("omci-message-response for not registered transCorrId", log.Fields{"deviceID": oo.deviceID})
+		logger.Errorw("omci-message-response for not registered transCorrId", log.Fields{"device-id": oo.deviceID})
 		return fmt.Errorf("could not find registered response handler tor transCorrId %s", oo.deviceID)
 	}
 
@@ -496,11 +498,11 @@
 			return fmt.Errorf("failed to fetch device %s", oo.deviceID)
 		}
 
-		logger.Debugw("omci-message-sending", log.Fields{"fromDeviceType": oo.pBaseDeviceHandler.DeviceType,
-			"toDeviceType": oo.pBaseDeviceHandler.ProxyAddressType,
-			"onuDeviceID":  oo.deviceID, "proxyDeviceID": oo.pBaseDeviceHandler.ProxyAddressID})
-		logger.Debugw("omci-message-to-send:",
-			log.Fields{"TxOmciMessage": hex.EncodeToString(omciTxRequest.txFrame)})
+		logger.Debugw("omci-message-to-send:", log.Fields{
+			"TxOmciMessage": hex.EncodeToString(omciTxRequest.txFrame),
+			"device-id":     oo.deviceID,
+			"toDeviceType":  oo.pBaseDeviceHandler.ProxyAddressType,
+			"proxyDeviceID": oo.pBaseDeviceHandler.ProxyAddressID})
 
 		omciMsg := &ic.InterAdapterOmciMessage{Message: omciTxRequest.txFrame}
 		if sendErr := oo.adapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
@@ -1656,6 +1658,190 @@
 	return nil
 }
 
+func (oo *omciCC) sendDeleteGemIWTP(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aInstID uint16) *me.ManagedEntity {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw("send GemIwTp-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+	meParams := me.ParamData{EntityID: aInstID}
+	meInstance, omciErr := me.NewGemInterworkingTerminationPoint(meParams)
+	if omciErr.GetError() == nil {
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType,
+			omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorw("Cannot encode GemIwTp for delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+			//  return (dual format) error code that can be used at caller for immediate error treatment
+			//  (relevant to all used sendXX() methods and their error conditions)
+			return nil
+		}
+
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize GemIwTp delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+
+		omciRxCallbackPair := callbackPair{
+			cbKey:   tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		}
+		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send GemIwTp delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+		logger.Debug("send GemIwTp-Delete-msg done")
+		return meInstance
+	}
+	logger.Errorw("Cannot generate GemIwTp Instance for delete", log.Fields{
+		"Err": omciErr.GetError(), "device-id": oo.deviceID})
+	return nil
+}
+
+func (oo *omciCC) sendDeleteGemNCTP(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aInstID uint16) *me.ManagedEntity {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw("send GemNCtp-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+	meParams := me.ParamData{EntityID: aInstID}
+	meInstance, omciErr := me.NewGemPortNetworkCtp(meParams)
+	if omciErr.GetError() == nil {
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType,
+			omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorw("Cannot encode GemNCtp for delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+			//  return (dual format) error code that can be used at caller for immediate error treatment
+			//  (relevant to all used sendXX() methods and their error conditions)
+			return nil
+		}
+
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize GemNCtp delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+
+		omciRxCallbackPair := callbackPair{
+			cbKey:   tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		}
+		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send GemNCtp delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+		logger.Debug("send GemNCtp-Delete-msg done")
+		return meInstance
+	}
+	logger.Errorw("Cannot generate GemNCtp Instance for delete", log.Fields{
+		"Err": omciErr.GetError(), "device-id": oo.deviceID})
+	return nil
+}
+
+func (oo *omciCC) sendDeleteDot1PMapper(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aInstID uint16) *me.ManagedEntity {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw("send .1pMapper-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+	meParams := me.ParamData{EntityID: aInstID}
+	meInstance, omciErr := me.NewIeee8021PMapperServiceProfile(meParams)
+	if omciErr.GetError() == nil {
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType,
+			omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorw("Cannot encode .1pMapper for delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+			//  return (dual format) error code that can be used at caller for immediate error treatment
+			//  (relevant to all used sendXX() methods and their error conditions)
+			return nil
+		}
+
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize .1pMapper delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+
+		omciRxCallbackPair := callbackPair{
+			cbKey:   tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		}
+		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send .1pMapper delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+		logger.Debug("send .1pMapper-Delete-msg done")
+		return meInstance
+	}
+	logger.Errorw("Cannot generate .1pMapper Instance for delete", log.Fields{
+		"Err": omciErr.GetError(), "device-id": oo.deviceID})
+	return nil
+}
+
+func (oo *omciCC) sendDeleteMBPConfigData(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aInstID uint16) *me.ManagedEntity {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw("send MBPCD-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+	meParams := me.ParamData{EntityID: aInstID}
+	meInstance, omciErr := me.NewMacBridgePortConfigurationData(meParams)
+	if omciErr.GetError() == nil {
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType,
+			omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorw("Cannot encode MBPCD for delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+			//  return (dual format) error code that can be used at caller for immediate error treatment
+			//  (relevant to all used sendXX() methods and their error conditions)
+			return nil
+		}
+
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize MBPCD delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+
+		omciRxCallbackPair := callbackPair{
+			cbKey:   tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		}
+		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send MBPCD delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+		logger.Debug("send MBPCD-Delete-msg done")
+		return meInstance
+	}
+	logger.Errorw("Cannot generate MBPCD Instance for delete", log.Fields{
+		"Err": omciErr.GetError(), "device-id": oo.deviceID})
+	return nil
+}
+
 // nolint: unused
 func (oo *omciCC) sendCreateMulticastGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index 71c1a8f..eb3b65f 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -608,6 +608,16 @@
 func (oFsm *UniVlanConfigFsm) enterConfigVtfd(e *fsm.Event) {
 	//mutex protection is required for possible concurrent access to FSM members
 	oFsm.mutexFlowParams.Lock()
+	if len(oFsm.uniVlanFlowParamsSlice) == 0 {
+		//possibly the entry is not valid anymore based on intermediate delete requests
+		//just a basic protection ...
+		oFsm.mutexFlowParams.Unlock()
+		pConfigVlanStateAFsm := oFsm.pAdaptFsm
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pConfigVlanStateAFsm)
+		return
+	}
 	if oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// meaning transparent setup - no specific VTFD setting required
 		oFsm.mutexFlowParams.Unlock()
@@ -705,7 +715,16 @@
 		}(pConfigVlanStateBaseFsm)
 		return
 	}
-
+	if uint8(len(oFsm.uniVlanFlowParamsSlice)) < oFsm.configuredUniFlow {
+		//possibly the entry is not valid anymore based on intermediate delete requests
+		//just a basic protection ...
+		oFsm.mutexFlowParams.Unlock()
+		pConfigVlanStateAFsm := oFsm.pAdaptFsm
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pConfigVlanStateAFsm)
+		return
+	}
 	if oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// meaning transparent setup - no specific VTFD setting required
 		oFsm.mutexFlowParams.Unlock()
@@ -1198,6 +1217,17 @@
 	} //first flow element
 
 	oFsm.mutexFlowParams.Lock()
+	if uint8(len(oFsm.uniVlanFlowParamsSlice)) < aFlowEntryNo {
+		//possibly the entry is not valid anymore based on intermediate delete requests
+		//just a basic protection ...
+		oFsm.mutexFlowParams.Unlock()
+		pConfigVlanStateAFsm := oFsm.pAdaptFsm
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pConfigVlanStateAFsm)
+		return
+	}
+
 	if oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		//transparent transmission required
 		oFsm.mutexFlowParams.Unlock()
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index ee52b13..102f32d 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -72,6 +72,7 @@
 	//maxQueueSize     uint16
 	queueSchedPolicy string
 	queueWeight      uint8
+	removeIndex      uint16
 }
 
 //refers to one tcont and its properties and all assigned GemPorts and their properties
@@ -99,6 +100,7 @@
 	procResult               map[uniTP]error //error indication of processing
 	mutexTPState             sync.Mutex
 	tpProfileExists          map[uniTP]bool
+	mapRemoveGemEntry        map[uniTP]*gemPortParamStruct //per UNI: pointer to GemEntry to be removed
 }
 
 //newOnuUniTechProf returns the instance of a OnuUniTechProf
@@ -114,6 +116,7 @@
 	onuTP.mapPonAniConfig = make(map[uniTP]*tcontGemList)
 	onuTP.procResult = make(map[uniTP]error)
 	onuTP.tpProfileExists = make(map[uniTP]bool)
+	onuTP.mapRemoveGemEntry = make(map[uniTP]*gemPortParamStruct)
 	baseKvStorePath := fmt.Sprintf(cBasePathTechProfileKVStore, aDeviceHandler.pOpenOnuAc.cm.Backend.PathPrefix)
 	onuTP.techProfileKVStore = aDeviceHandler.setBackend(baseKvStorePath)
 	if onuTP.techProfileKVStore == nil {
@@ -144,7 +147,7 @@
 	return onuTP.procResult[uniTP{uniID: aUniID, tpID: aTpID}]
 }
 
-// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
+// configureUniTp checks existing tp resources to configure and starts the corresponding OMCI configuation of the UNI port
 // all possibly blocking processing must be run in background to allow for deadline supervision!
 // but take care on sequential background processing when needed (logical dependencies)
 //   use waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) for internal synchronization
@@ -160,7 +163,8 @@
 		return
 	}
 	if onuTP.techProfileKVStore == nil {
-		logger.Debug("techProfileKVStore not set - abort")
+		logger.Errorw("techProfileKVStore not set - abort",
+			log.Fields{"device-id": onuTP.deviceID})
 		onuTP.procResult[uniTpKey] = errors.New("techProfile config aborted: techProfileKVStore not set")
 		return
 	}
@@ -210,7 +214,7 @@
 			// and abort the processing here
 			return
 		}
-		logger.Debugw("tech-profile related configuration aborted on read",
+		logger.Errorw("tech-profile related configuration aborted on read",
 			log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
 		onuTP.procResult[uniTpKey] = fmt.Errorf("techProfile config aborted: tech-profile read issue for %d on %s",
 			aUniID, onuTP.deviceID)
@@ -224,10 +228,15 @@
 	if existPA {
 		if valuePA != nil {
 			//Config data for this uni and and at least TCont Index 0 exist
-			go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, tpID, pCurrentUniPort, processingStep)
+			if err := onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, tpID, pCurrentUniPort, processingStep); err != nil {
+				logger.Errorw("tech-profile related FSM could not be started",
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
+				onuTP.procResult[uniTpKey] = err
+				return
+			}
 			if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
 				//timeout or error detected
-				logger.Debugw("tech-profile related configuration aborted on set",
+				logger.Errorw("tech-profile related configuration aborted on set",
 					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
 
 				onuTP.procResult[uniTpKey] = fmt.Errorf("techProfile config aborted: Omci AniSideConfig failed %d on %s",
@@ -240,7 +249,7 @@
 			}
 		} else {
 			// strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
-			logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
+			logger.Errorw("no Tcont/Gem data for this UNI found - abort", log.Fields{
 				"device-id": onuTP.deviceID, "uni-id": aUniID})
 
 			onuTP.procResult[uniTpKey] = fmt.Errorf("techProfile config aborted: no Tcont/Gem data found for this UNI %d on %s",
@@ -248,7 +257,7 @@
 			return
 		}
 	} else {
-		logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
+		logger.Errorw("no PonAni data for this UNI found - abort", log.Fields{
 			"device-id": onuTP.deviceID, "uni-id": aUniID})
 
 		onuTP.procResult[uniTpKey] = fmt.Errorf("techProfile config aborted: no AniSide data found for this UNI %d on %s",
@@ -419,8 +428,8 @@
 
 	//logger does not simply output the given structures, just give some example debug values
 	logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
-		"device-id": onuTP.deviceID,
-		"AllocId":   onuTP.mapPonAniConfig[uniTPKey].tcontParams.allocID})
+		"device-id": onuTP.deviceID, "uni-id": aUniID,
+		"AllocId": onuTP.mapPonAniConfig[uniTPKey].tcontParams.allocID})
 	for gemIndex, gemEntry := range onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams {
 		logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
 			"GemIndex":        gemIndex,
@@ -432,19 +441,209 @@
 }
 
 func (onuTP *onuUniTechProf) setAniSideConfigFromTechProfile(
-	ctx context.Context, aUniID uint8, aTpID uint8, apCurrentUniPort *onuUniPort, aProcessingStep uint8) {
+	ctx context.Context, aUniID uint8, aTpID uint8, apCurrentUniPort *onuUniPort, aProcessingStep uint8) error {
 
 	//OMCI transfer of ANI data acc. to mapPonAniConfig
 	// also the FSM's are running in background,
-	//   hence we have to make sure they indicate 'success' success on chTpConfigProcessingStep with aProcessingStep
+	//   hence we have to make sure they indicate 'success' on chTpConfigProcessingStep with aProcessingStep
 	uniTPKey := uniTP{uniID: aUniID, tpID: aTpID}
 	if onuTP.pAniConfigFsm == nil {
-		onuTP.createAniConfigFsm(aUniID, aTpID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
+		return onuTP.createAniConfigFsm(aUniID, aTpID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
 	} else if _, ok := onuTP.pAniConfigFsm[uniTPKey]; !ok {
-		onuTP.createAniConfigFsm(aUniID, aTpID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
-	} else { //AniConfigFsm already init
-		onuTP.runAniConfigFsm(aProcessingStep, aUniID, aTpID)
+		return onuTP.createAniConfigFsm(aUniID, aTpID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
 	}
+	//AniConfigFsm already init
+	return onuTP.runAniConfigFsm(aniEvStart, aProcessingStep, aUniID, aTpID)
+}
+
+// deleteTpResource removes Resources from the ONU's specified Uni
+func (onuTP *onuUniTechProf) deleteTpResource(ctx context.Context,
+	aUniID uint8, aTpID uint8, aPathString string, aResource resourceEntry, aEntryID uint32,
+	wg *sync.WaitGroup) {
+	defer wg.Done()
+	logger.Debugw("will remove TP resources from ONU's UNI", log.Fields{
+		"device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString, "Resource": aResource})
+	uniTPKey := uniTP{uniID: aUniID, tpID: aTpID}
+
+	if cResourceGemPort == aResource {
+		logger.Debugw("remove GemPort from the list of existing ones of the TP", log.Fields{
+			"device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString, "GemPort": aEntryID})
+
+		// check if the requested GemPort exists in the DB, indicate it to the FSM
+		// store locally to remove it from DB later on success
+		pLocAniConfigOnUni := onuTP.mapPonAniConfig[uniTPKey]
+		if pLocAniConfigOnUni == nil {
+			// No relevant entry exists anymore - acknowledge success
+			logger.Debugw("AniConfig or GemEntry do not exists in DB", log.Fields{
+				"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID})
+			return
+		}
+		for gemIndex, gemEntry := range pLocAniConfigOnUni.mapGemPortParams {
+			if gemEntry.gemPortID == uint16(aEntryID) {
+				//GemEntry to be deleted found
+				gemEntry.removeIndex = gemIndex //store the index for later removal
+				onuTP.mapRemoveGemEntry[uniTPKey] = pLocAniConfigOnUni.mapGemPortParams[gemIndex]
+				logger.Debugw("Remove-GemEntry stored", log.Fields{
+					"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID, "GemIndex": gemIndex})
+				break //abort loop, always only one GemPort to remove
+			}
+		}
+		if onuTP.mapRemoveGemEntry[uniTPKey] == nil {
+			logger.Errorw("GemPort removal aborted - GemPort not found",
+				log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID, "GemPort": aEntryID})
+			/* Do not set some error indication to the outside system interface on delete
+			   assume there is nothing to be deleted internally and hope a new config request will recover the situation
+			 onuTP.procResult[uniTpKey] = fmt.Errorf("GemPort removal aborted: GemPort not found %d for %d on %s",
+				aEntryID, aUniID, onuTP.deviceID)
+			*/
+			return
+		}
+		if onuTP.baseDeviceHandler.ReadyForSpecificOmciConfig {
+			// check that the TpConfigRequest was done before
+			//   -> that is implicitly done using the AniConfigFsm,
+			//      which must be in the according state to remove something
+			// initiate OMCI GemPort related removal
+			var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
+			//   hence we have to make sure they indicate 'success' on chTpConfigProcessingStep with aProcessingStep
+			if onuTP.pAniConfigFsm == nil {
+				logger.Errorw("abort GemPort removal - no AniConfigFsm available",
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
+				/* Do not set some error indication to the outside system interface on delete (see above)
+				onuTP.procResult[uniTpKey] = fmt.Errorf("GemPort removal aborted: no AniConfigFsm available %d on %s",
+					aUniID, onuTP.deviceID)
+				*/
+				//if the FSM is not valid, also TP related remove data should not be valid:
+				// remove GemPort from config DB
+				delete(onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams, onuTP.mapRemoveGemEntry[uniTPKey].removeIndex)
+				// remove the removeEntry
+				delete(onuTP.mapRemoveGemEntry, uniTPKey)
+				return
+			}
+			if _, ok := onuTP.pAniConfigFsm[uniTPKey]; !ok {
+				logger.Errorw("abort GemPort removal - no AniConfigFsm available for this uni/tp",
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID})
+				/* Do not set some error indication to the outside system interface on delete (see above)
+				onuTP.procResult[uniTpKey] = fmt.Errorf("GemPort removal aborted: no AniConfigFsm available %d on %s for tpid",
+					aUniID, onuTP.deviceID, aTpID)
+				*/
+				//if the FSM is not valid, also TP related remove data should not be valid:
+				// remove GemPort from config DB
+				delete(onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams, onuTP.mapRemoveGemEntry[uniTPKey].removeIndex)
+				// remove the removeEntry
+				delete(onuTP.mapRemoveGemEntry, uniTPKey)
+				return
+			}
+			if nil != onuTP.runAniConfigFsm(aniEvRemGemiw, processingStep, aUniID, aTpID) {
+				//even if the FSM invocation did not work we don't indicate a problem within procResult
+				//errors could exist also because there was nothing to delete - so we just accept that as 'deleted'
+				//TP related data cleared by FSM error treatment or re-used by FSM error-recovery (if implemented)
+				return
+			}
+			if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
+				//timeout or error detected
+				logger.Errorw("GemPort removal aborted - Omci AniSideConfig failed",
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
+				//even if the FSM delete execution did not work we don't indicate a problem within procResult
+				//we should never respond to delete with error ...
+				//this issue here means that the AniConfigFsm has not finished successfully
+				//which requires to reset it to allow for new usage, e.g. also on a different UNI
+				//(without that it would be reset on device down indication latest)
+				_ = onuTP.pAniConfigFsm[uniTPKey].pAdaptFsm.pFsm.Event(aniEvReset)
+				//TP related data cleared by FSM error treatment or re-used by FSM error-recovery (if implemented)
+				return
+			}
+		} else {
+			logger.Debugw("uniPonAniConfigFsm delete Gem on OMCI skipped based on device state", log.Fields{
+				"device-id": onuTP.deviceID, "device-state": onuTP.baseDeviceHandler.deviceReason})
+		}
+		// remove GemPort from config DB
+		delete(onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams, onuTP.mapRemoveGemEntry[uniTPKey].removeIndex)
+		// remove the removeEntry
+		delete(onuTP.mapRemoveGemEntry, uniTPKey)
+		//  deviceHandler StatusEvent (reason update) (see end of function) is only generated in case some element really was removed
+	} else { //if cResourceTcont == aResource {
+		logger.Debugw("reset TCont with AllocId", log.Fields{
+			"device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString, "allocId": aEntryID})
+
+		// check if the TCont with the indicated AllocId exists in the DB, indicate its EntityId to the FSM
+		pLocAniConfigOnUni := onuTP.mapPonAniConfig[uniTPKey]
+		if pLocAniConfigOnUni == nil {
+			// No relevant entry exists anymore - acknowledge success
+			logger.Debugw("AniConfig or TCont entry do not exists in DB", log.Fields{
+				"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID})
+			return
+		}
+		if pLocAniConfigOnUni.tcontParams.allocID != uint16(aEntryID) {
+			logger.Errorw("TCont removal aborted - indicated AllocId not found",
+				log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID, "AllocId": aEntryID})
+			/* Do not set some error indication to the outside system interface on delete
+			   assume there is nothing to be deleted internally and hope a new config request will recover the situation
+			 onuTP.procResult[uniTpKey] = fmt.Errorf("TCont removal aborted: AllocId not found %d for %d on %s",
+				aEntryID, aUniID, onuTP.deviceID)
+			*/
+			return
+		}
+		//T-Cont to be reset found
+		logger.Debugw("Reset-T-Cont AllocId found - valid", log.Fields{
+			"device-id": onuTP.deviceID, "uni-id": aUniID, "AllocId": aEntryID})
+		if onuTP.pAniConfigFsm == nil {
+			logger.Errorw("no TCont removal on OMCI - no AniConfigFsm available",
+				log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
+			/* Do not set some error indication to the outside system interface on delete (see above)
+			onuTP.procResult[uniTpKey] = fmt.Errorf("TCont cleanup aborted: no AniConfigFsm available %d on %s",
+				aUniID, onuTP.deviceID)
+			*/
+			//if the FSM is not valid, also TP related data should not be valid - clear the internal store profile data
+			onuTP.clearAniSideConfig(aUniID, aTpID)
+			return
+		}
+		if _, ok := onuTP.pAniConfigFsm[uniTPKey]; !ok {
+			logger.Errorw("no TCont removal on OMCI - no AniConfigFsm available for this uni/tp",
+				log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID, "tp-id": aTpID})
+			//even if the FSM invocation did not work we don't indicate a problem within procResult
+			//errors could exist also because there was nothing to delete - so we just accept that as 'deleted'
+			//if the FSM is not valid, also TP related data should not be valid - clear the internal store profile data
+			onuTP.clearAniSideConfig(aUniID, aTpID)
+			return
+		}
+		if onuTP.baseDeviceHandler.ReadyForSpecificOmciConfig {
+			// check that the TpConfigRequest was done before
+			//   -> that is implicitly done using the AniConfigFsm,
+			//      which must be in the according state to remove something
+			// initiate OMCI TCont related cleanup
+			var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
+			//   hence we have to make sure they indicate 'success' on chTpConfigProcessingStep with aProcessingStep
+			if nil != onuTP.runAniConfigFsm(aniEvRemTcontPath, processingStep, aUniID, aTpID) {
+				//even if the FSM invocation did not work we don't indicate a problem within procResult
+				//errors could exist also because there was nothing to delete - so we just accept that as 'deleted'
+				//TP related data cleared by FSM error treatment or re-used by FSM error-recovery (if implemented)
+				return
+			}
+			if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
+				//timeout or error detected
+				logger.Errorw("TCont cleanup aborted - Omci AniSideConfig failed",
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
+				//even if the FSM delete execution did not work we don't indicate a problem within procResult
+				//we should never respond to delete with error ...
+				//this issue here means that the AniConfigFsm has not finished successfully
+				//which requires to reset it to allow for new usage, e.g. also on a different UNI
+				//(without that it would be reset on device down indication latest)
+				_ = onuTP.pAniConfigFsm[uniTPKey].pAdaptFsm.pFsm.Event(aniEvReset)
+				//TP related data cleared by FSM error treatment or re-used by FSM error-recovery (if implemented)
+				return
+			}
+		} else {
+			logger.Debugw("uniPonAniConfigFsm TCont cleanup on OMCI skipped based on device state", log.Fields{
+				"device-id": onuTP.deviceID, "device-state": onuTP.baseDeviceHandler.deviceReason})
+		}
+		//clear the internal store profile data
+		onuTP.clearAniSideConfig(aUniID, aTpID)
+		// reset also the FSM in order to admit a new OMCI configuration in case a new profile is created
+		// FSM stop maybe encapsulated as OnuTP method - perhaps later in context of module splitting
+		_ = onuTP.pAniConfigFsm[uniTPKey].pAdaptFsm.pFsm.Event(aniEvReset)
+	}
+	// generate deviceHandler StatusEvent in case the FSM was not invoked
+	go onuTP.baseDeviceHandler.deviceProcStatusUpdate(OmciAniResourceRemoved)
 }
 
 func (onuTP *onuUniTechProf) waitForTimeoutOrCompletion(
@@ -468,85 +667,31 @@
 
 // createUniLockFsm initializes and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
 func (onuTP *onuUniTechProf) createAniConfigFsm(aUniID uint8, aTpID uint8,
-	apCurrentUniPort *onuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
+	apCurrentUniPort *onuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) error {
 	logger.Debugw("createAniConfigFsm", log.Fields{"device-id": onuTP.deviceID})
 	chAniConfigFsm := make(chan Message, 2048)
 	uniTPKey := uniTP{uniID: aUniID, tpID: aTpID}
 	pDevEntry := onuTP.baseDeviceHandler.getOnuDeviceEntry(true)
 	if pDevEntry == nil {
 		logger.Errorw("No valid OnuDevice - aborting", log.Fields{"device-id": onuTP.deviceID})
-		return
+		return fmt.Errorf("no valid OnuDevice: %s", onuTP.deviceID)
 	}
 	pAniCfgFsm := newUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
 		pDevEntry.pOnuDB, aTpID, devEvent,
 		"AniConfigFsm", onuTP.baseDeviceHandler, chAniConfigFsm)
-	if pAniCfgFsm != nil {
-		if onuTP.pAniConfigFsm == nil {
-			onuTP.pAniConfigFsm = make(map[uniTP]*uniPonAniConfigFsm)
-		}
-		onuTP.pAniConfigFsm[uniTPKey] = pAniCfgFsm
-		onuTP.runAniConfigFsm(aProcessingStep, aUniID, aTpID)
-	} else {
+	if pAniCfgFsm == nil {
 		logger.Errorw("AniConfigFSM could not be created - abort!!", log.Fields{"device-id": onuTP.deviceID})
+		return fmt.Errorf("could not create AniConfigFSM: %s", onuTP.deviceID)
 	}
-}
-
-// deleteTpResource removes Resources from the ONU's specified Uni
-func (onuTP *onuUniTechProf) deleteTpResource(ctx context.Context,
-	aUniID uint8, aPathString string, aResource resourceEntry, aEntryID uint32,
-	wg *sync.WaitGroup) {
-	defer wg.Done()
-	logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
-		"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
-	tpID, err := GetTpIDFromTpPath(aPathString)
-	if err != nil {
-		logger.Errorw("error-extracting-tp-id-from-tp-path", log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString})
-		return
+	if onuTP.pAniConfigFsm == nil {
+		onuTP.pAniConfigFsm = make(map[uniTP]*uniPonAniConfigFsm)
 	}
-	uniTpKey := uniTP{uniID: aUniID, tpID: tpID}
-	if cResourceGemPort == aResource {
-		logger.Debugw("remove GemPort from the list of existing ones of the TP", log.Fields{
-			"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "entry": aEntryID})
-		// check if the requested GemPort exists in the DB
-		// check that the TpConfigRequest was done
-		// initiate OMCI GemPort related removal
-		// remove GemPort from config DB
-		// dev reason update? (for the moment not yet done here!)
-	} else { //if cResourceTcont == aResource {
-		//the TechProfile indicated by path is considered for removal
-		//  by now we do not clear the OMCI related configuration (to be done later)
-		//  so we use this position here just to remove the internal stored profile data
-		//    (needed for checking the existence of the TechProfile after some profile delete)
-		//  at the oment we only admit 1 TechProfile (T-Cont), so by now we can just remove the only existing TechProfile
-		//  TODO: To be updated with multi-T-Cont implementation
-		logger.Debugw("DeleteTcont clears the existing internal profile", log.Fields{
-			"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
-
-		onuTP.clearAniSideConfig(aUniID, tpID)
-		// reset also the FSM in order to admit a new OMCI configuration in case a new profile is created
-		// FSM stop maybe encapsulated as OnuTP method - perhaps later in context of module splitting
-		if onuTP.pAniConfigFsm != nil {
-			_ = onuTP.pAniConfigFsm[uniTpKey].pAdaptFsm.pFsm.Event(aniEvReset)
-		}
-
-		//TODO!!! - the real processing could look like that (for starting the removal, where the clearAniSideConfig is done implicitly):
-		//delete the given resource from ONU OMCI config and data base - as background routine
-		/*
-			var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
-			go onuTp.deleteAniResource(ctx, processingStep)
-			if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
-				//timeout or error detected
-				return
-			}
-		*/
-	}
-	//if implemented, the called FSM would generate an adequate event if config has been done,
-	//  by now we just stimulate this event here as 'done' - TODO!!: to be removed after full implementation
-	go onuTP.baseDeviceHandler.deviceProcStatusUpdate(OmciAniResourceRemoved)
+	onuTP.pAniConfigFsm[uniTPKey] = pAniCfgFsm
+	return onuTP.runAniConfigFsm(aniEvStart, aProcessingStep, aUniID, aTpID)
 }
 
 // runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for  ANI side configuration
-func (onuTP *onuUniTechProf) runAniConfigFsm(aProcessingStep uint8, aUniID uint8, aTpID uint8) {
+func (onuTP *onuUniTechProf) runAniConfigFsm(aEvent string, aProcessingStep uint8, aUniID uint8, aTpID uint8) error {
 	/*  Uni related ANI config procedure -
 	 ***** should run via 'aniConfigDone' state and generate the argument requested event *****
 	 */
@@ -554,26 +699,32 @@
 
 	pACStatemachine := onuTP.pAniConfigFsm[uniTpKey].pAdaptFsm.pFsm
 	if pACStatemachine != nil {
-		if pACStatemachine.Is(aniStDisabled) {
-			//FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
-			onuTP.pAniConfigFsm[uniTpKey].setFsmCompleteChannel(onuTP.chTpConfigProcessingStep, aProcessingStep)
-			if err := pACStatemachine.Event(aniEvStart); err != nil {
-				logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
+		if aEvent == aniEvStart {
+			if !pACStatemachine.Is(aniStDisabled) {
+				logger.Errorw("wrong state of AniConfigFSM to start - want: Disabled", log.Fields{
+					"have": pACStatemachine.Current(), "device-id": onuTP.deviceID})
 				// maybe try a FSM reset and then again ... - TODO!!!
-			} else {
-				/***** AniConfigFSM started */
-				logger.Debugw("AniConfigFSM started", log.Fields{
-					"state": pACStatemachine.Current(), "device-id": onuTP.deviceID})
+				return fmt.Errorf("wrong state of AniConfigFSM to start: %s", onuTP.deviceID)
 			}
-		} else {
-			logger.Warnw("wrong state of AniConfigFSM - want: disabled", log.Fields{
+		} else if !pACStatemachine.Is(aniStConfigDone) {
+			logger.Errorw("wrong state of AniConfigFSM to remove - want: ConfigDone", log.Fields{
 				"have": pACStatemachine.Current(), "device-id": onuTP.deviceID})
-			// maybe try a FSM reset and then again ... - TODO!!!
+			return fmt.Errorf("wrong state of AniConfigFSM to remove: %s", onuTP.deviceID)
 		}
-	} else {
-		logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"device-id": onuTP.deviceID})
-		// maybe try a FSM reset and then again ... - TODO!!!
+		//FSM init requirement to get informed about FSM completion! (otherwise timeout of the TechProf config)
+		onuTP.pAniConfigFsm[uniTpKey].setFsmCompleteChannel(onuTP.chTpConfigProcessingStep, aProcessingStep)
+		if err := pACStatemachine.Event(aEvent); err != nil {
+			logger.Errorw("AniConfigFSM: can't trigger event", log.Fields{"err": err})
+			return fmt.Errorf("can't trigger event in AniConfigFSM: %s", onuTP.deviceID)
+		}
+		/***** AniConfigFSM event notified */
+		logger.Debugw("AniConfigFSM event notified", log.Fields{
+			"state": pACStatemachine.Current(), "device-id": onuTP.deviceID, "event": aEvent})
+		return nil
 	}
+	logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"device-id": onuTP.deviceID})
+	// maybe try a FSM reset and then again ... - TODO!!!
+	return fmt.Errorf("stateMachine AniConfigFSM invalid: %s", onuTP.deviceID)
 }
 
 // clearAniSideConfig deletes internal TechProfile related data connected to the requested UniPort and TpID