OnuUpgrade: Use download state only for image download (revert activity progress indication on activate/commit),
consistent state indication on abort, improval of software download abortion

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I2ca6e22662bc3bbede355176fbb4b2171add3f35
diff --git a/internal/pkg/swupg/omci_onu_upgrade.go b/internal/pkg/swupg/omci_onu_upgrade.go
index dbcb141..43ad621 100755
--- a/internal/pkg/swupg/omci_onu_upgrade.go
+++ b/internal/pkg/swupg/omci_onu_upgrade.go
@@ -49,7 +49,39 @@
 	//cOmciDownloadCompleteTimeout = 5400 //in s for the complete timeout (may be better scale to image size/ noOfWindows)
 )
 
-// events of config PON ANI port FSM
+// tEndSwDlResponseResult - Response result from EndSwDownload as used in channel indication
+type tUpgradePhase uint8
+
+const (
+	// undefined phase
+	cUpgradeUndefined tUpgradePhase = iota
+	// downloading image
+	cUpgradeDownloading
+	// image downloaded
+	cUpgradeDownloaded
+	// activating image
+	cUpgradeActivating
+	// image activated
+	cUpgradeActivated
+	// committing image
+	cUpgradeCommitting
+	// image committed
+	cUpgradeCommitted
+)
+
+// tEndSwDlResponseResult - Response result from EndSwDownload as used in channel indication
+type tEndSwDlResponseResult uint8
+
+const (
+	// response success
+	cEndSwDlResponseSuccess tEndSwDlResponseResult = iota
+	// response busy (repeat)
+	cEndSwDlResponseBusy
+	// response error or abort waiting for response
+	cEndSwDlResponseAbort
+)
+
+// upgrade FSM related events
 const (
 	UpgradeEvStart              = "UpgradeEvStart"
 	UpgradeEvDisable            = "UpgradeEvDisable"
@@ -77,7 +109,7 @@
 	UpgradeEvAbortSwDownload = "UpgradeEvAbortSwDownload"
 )
 
-// states of config PON ANI port FSM
+// upgrade FSM related states
 const (
 	UpgradeStDisabled           = "UpgradeStDisabled"
 	UpgradeStStarting           = "UpgradeStStarting"
@@ -130,6 +162,7 @@
 	downloadToOnuTimeout4MB          time.Duration //timeout for downloading the image to the ONU for a 4MB image slice
 	omciSectionInterleaveDelay       time.Duration //DownloadSectionInterleave delay in milliseconds
 	delayEndSwDl                     bool          //flag to provide a delay between last section and EndSwDl
+	repeatAbort                      bool          //flag to indicate if OMCI EndSwDownload (abort) is to be repeated
 	pLastTxMeInstance                *me.ManagedEntity
 	waitCountEndSwDl                 uint8         //number, how often is waited for EndSwDl at maximum
 	waitDelayEndSwDl                 time.Duration //duration, how long is waited before next request on EndSwDl
@@ -147,11 +180,13 @@
 	mutexAbortRequest                sync.RWMutex
 	abortRequested                   voltha.ImageState_ImageFailureReason
 	conditionalCancelRequested       bool
+	upgradePhase                     tUpgradePhase
 	volthaDownloadState              voltha.ImageState_ImageDownloadState
 	volthaDownloadReason             voltha.ImageState_ImageFailureReason
 	volthaImageState                 voltha.ImageState_ImageActivationState
+	downloadReasonCached             voltha.ImageState_ImageFailureReason
 	isEndSwDlOpen                    bool
-	chReceiveAbortEndSwDlResponse    chan bool
+	chReceiveAbortEndSwDlResponse    chan tEndSwDlResponseResult
 }
 
 //NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
@@ -171,7 +206,8 @@
 		downloadToOnuTimeout4MB:     apDeviceHandler.GetDlToOnuTimeout4M(),
 		waitCountEndSwDl:            cWaitCountEndSwDl,
 		waitDelayEndSwDl:            cWaitDelayEndSwDlSeconds,
-		volthaDownloadState:         voltha.ImageState_DOWNLOAD_STARTED, //if FSM created we can assume that the download (to adapter) really started
+		upgradePhase:                cUpgradeUndefined,
+		volthaDownloadState:         voltha.ImageState_DOWNLOAD_UNKNOWN,
 		volthaDownloadReason:        voltha.ImageState_NO_ERROR,
 		volthaImageState:            voltha.ImageState_IMAGE_UNKNOWN,
 		abortRequested:              voltha.ImageState_NO_ERROR,
@@ -179,7 +215,7 @@
 	instFsm.chReceiveExpectedResponse = make(chan bool)
 	instFsm.chAdapterDlReady = make(chan bool)
 	instFsm.chOnuDlReady = make(chan bool)
-	instFsm.chReceiveAbortEndSwDlResponse = make(chan bool)
+	instFsm.chReceiveAbortEndSwDlResponse = make(chan tEndSwDlResponseResult)
 
 	instFsm.PAdaptFsm = cmn.NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
 	if instFsm.PAdaptFsm == nil {
@@ -224,7 +260,7 @@
 			{Name: UpgradeEvReset, Src: []string{UpgradeStStarting, UpgradeStWaitingAdapterDL, UpgradeStPreparingDL, UpgradeStDLSection,
 				UpgradeStVerifyWindow, UpgradeStDLSection, UpgradeStFinalizeDL, UpgradeStWaitEndDL, UpgradeStCheckImageName,
 				UpgradeStWaitForActivate,
-				UpgradeStCommitSw, UpgradeStCheckCommitted},
+				UpgradeStCommitSw, UpgradeStCheckCommitted, UpgradeStAbortingDL},
 				Dst: UpgradeStResetting},
 			{Name: UpgradeEvAbort, Src: []string{UpgradeStStarting, UpgradeStWaitingAdapterDL, UpgradeStPreparingDL, UpgradeStDLSection,
 				UpgradeStVerifyWindow, UpgradeStDLSection, UpgradeStFinalizeDL, UpgradeStWaitEndDL, UpgradeStCheckImageName,
@@ -313,8 +349,7 @@
 		oFsm.imageVersion = apImageRequest.Image.Version
 		oFsm.activateImage = apImageRequest.ActivateOnSuccess
 		oFsm.commitImage = apImageRequest.CommitOnSuccess
-		//TODO: currently straightforward options activate and commit are expected to be set and (unconditionally) done
-		//  for separate handling of these options the FSM must accordingly branch from the concerned states - later
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //state change indication for download request
 		oFsm.mutexUpgradeParams.Unlock()
 		_ = pBaseFsm.Event(UpgradeEvAdapterDownload) //no need to call the FSM event in background here
 		return nil
@@ -329,11 +364,11 @@
 //  called from 'new' API Activate_onu_image
 func (oFsm *OnuUpgradeFsm) SetActivationParamsRunning(ctx context.Context,
 	aImageIdentifier string, aCommit bool) error {
+	logger.Debugw(ctx, "OnuUpgradeFsm activate/commit parameter setting", log.Fields{
+		"device-id": oFsm.deviceID, "image-id": aImageIdentifier, "commit": aCommit})
 	oFsm.mutexUpgradeParams.Lock()
 	//set activate/commit independent from state, if FSM is already beyond concerned states, then it does not matter anyway
 	//  (as long as the Imageidentifier is correct)
-	logger.Debugw(ctx, "OnuUpgradeFsm activate/commit parameter setting", log.Fields{
-		"device-id": oFsm.deviceID, "image-id": aImageIdentifier, "commit": aCommit})
 	if aImageIdentifier != oFsm.imageIdentifier {
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: mismatching upgrade image", log.Fields{
 			"device-id": oFsm.deviceID, "request-image": aImageIdentifier, "fsm-image": oFsm.imageIdentifier})
@@ -343,18 +378,16 @@
 	}
 	oFsm.activateImage = true
 	oFsm.commitImage = aCommit
+	oFsm.mutexUpgradeParams.Unlock()
 	var pBaseFsm *fsm.FSM = nil
 	if oFsm.PAdaptFsm != nil {
 		pBaseFsm = oFsm.PAdaptFsm.PFsm
 	}
 	if pBaseFsm != nil {
 		if pBaseFsm.Is(UpgradeStWaitForActivate) {
-			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
-			oFsm.mutexUpgradeParams.Unlock()
 			logger.Debugw(ctx, "OnuUpgradeFsm finish waiting for activate", log.Fields{"device-id": oFsm.deviceID})
 			_ = pBaseFsm.Event(UpgradeEvRequestActivate) //no need to call the FSM event in background here
 		} else {
-			oFsm.mutexUpgradeParams.Unlock()
 			logger.Debugw(ctx, "OnuUpgradeFsm not (yet?) waiting for activate", log.Fields{
 				"device-id": oFsm.deviceID, "current FsmState": pBaseFsm.Current()})
 		}
@@ -382,8 +415,7 @@
 		oFsm.activateImage = true
 		oFsm.commitImage = aCommit
 		// indicate start of the upgrade activity
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
-		oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE      //as simply applied for inactive image
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING //state change indication for activate request
 		oFsm.mutexUpgradeParams.Unlock()
 		//directly request the FSM to activate the image
 		_ = pBaseFsm.Event(UpgradeEvRequestActivate) //no need to call the FSM event in background here
@@ -413,7 +445,6 @@
 			oFsm.deviceID))
 	}
 	oFsm.commitImage = true
-	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
 	oFsm.mutexUpgradeParams.Unlock()
 	var pBaseFsm *fsm.FSM = nil
 	if oFsm.PAdaptFsm != nil {
@@ -447,8 +478,7 @@
 		oFsm.InactiveImageMeID = aActiveImageID //upgrade state machines inactive ImageId is the new active ImageId
 		oFsm.imageVersion = aImageVersion
 		oFsm.commitImage = true
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
-		oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE        //as simply applied for active image
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTING //state change indication for activate request
 		oFsm.mutexUpgradeParams.Unlock()
 		//directly request the FSM to commit the image
 		_ = pBaseFsm.Event(UpgradeEvCommitSw) //no need to call the FSM event in background here
@@ -499,11 +529,8 @@
 func (oFsm *OnuUpgradeFsm) SetImageStateActive(ctx context.Context) {
 	oFsm.mutexUpgradeParams.Lock()
 	defer oFsm.mutexUpgradeParams.Unlock()
+	oFsm.upgradePhase = cUpgradeActivated
 	oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE
-	if !oFsm.commitImage {
-		//if commit is not additionally set, regard the upgrade activity as successful
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED //better choice would be 'UpgradeState=Succeeded'
-	}
 }
 
 //GetImageVersion delivers image-version of the running upgrade
@@ -535,31 +562,28 @@
 
 	// in any case (even if it might be automatically requested by above cancellation of waiting) ensure resetting the FSM
 	// specific here: See definition of state changes: some states are excluded from reset for possible later commit
-	PAdaptFsm := oFsm.PAdaptFsm
-	if PAdaptFsm != nil {
+	pAdaptFsm := oFsm.PAdaptFsm
+	if pAdaptFsm != nil {
 		// calling FSM events in background to avoid blocking of the caller
 		go func(aPAFsm *cmn.AdapterFsm) {
 			if aPAFsm.PFsm != nil {
 				if aPAFsm.PFsm.Is(UpgradeStWaitEndDL) {
 					oFsm.chReceiveExpectedResponse <- false //which aborts the FSM in WaitEndDL state
+				} else if aPAFsm.PFsm.Is(UpgradeStAbortingDL) {
+					oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseAbort //abort waiting on EndDownloadResponse
 				}
-				// in case of state-conditional request the
 
 				var err error
 				if abCompleteAbort {
+					// in case of unconditional abort request the ImageState is set immediately
 					oFsm.mutexUpgradeParams.Lock()
 					//any previous lingering conditional cancelRequest is superseded by this abortion
 					oFsm.conditionalCancelRequested = false
-					if aReason == voltha.ImageState_CANCELLED_ON_REQUEST {
-						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
-					} else {
-						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
-					}
 					oFsm.volthaDownloadReason = aReason
 					oFsm.mutexUpgradeParams.Unlock()
 					err = aPAFsm.PFsm.Event(UpgradeEvAbort) //as unconditional default FSM cancellation
 				} else {
-					//at conditional request the image states are set when reaching the reset state
+					//at conditional abort request the image states are set when reaching the reset state
 					oFsm.conditionalCancelRequested = true
 					err = aPAFsm.PFsm.Event(UpgradeEvReset) //as state-conditional default FSM cleanup
 				}
@@ -569,7 +593,7 @@
 						"device-id": oFsm.deviceID, "error": err})
 				}
 			} //else the FSM seems already to be in some released state
-		}(PAdaptFsm)
+		}(pAdaptFsm)
 	}
 }
 
@@ -606,9 +630,7 @@
 		fileLen, err = oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil || fileLen > int64(cMaxUint32) {
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
-		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
 		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
 			"device-id": oFsm.deviceID, "error": err, "length": fileLen})
@@ -628,9 +650,7 @@
 		oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil {
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
-		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
 		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
@@ -671,7 +691,7 @@
 	if err != nil {
 		logger.Errorw(ctx, "StartSwDl abort: can't send section", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 	oFsm.isEndSwDlOpen = true
@@ -687,6 +707,7 @@
 	var downloadSection []byte
 	FramePrint := false //default no printing of downloadSection frames
 	oFsm.mutexUpgradeParams.Lock()
+	oFsm.upgradePhase = cUpgradeDownloading //start of downloading image to ONU
 	if oFsm.nextDownloadSectionsAbsolute == 0 {
 		//debug print of first section frame
 		FramePrint = true
@@ -697,11 +718,7 @@
 		oFsm.mutexAbortRequest.RLock()
 		// this way out of the section download loop on abort request
 		if oFsm.abortRequested != voltha.ImageState_NO_ERROR {
-			if oFsm.abortRequested == voltha.ImageState_CANCELLED_ON_REQUEST {
-				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
-			} else {
-				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
-			}
+			//states are updated when entering the reset state ...
 			oFsm.volthaDownloadReason = oFsm.abortRequested
 			oFsm.mutexAbortRequest.RUnlock()
 			oFsm.mutexUpgradeParams.Unlock()
@@ -724,7 +741,6 @@
 			logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
 				"device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
 				"bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
-			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 			oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
 			oFsm.mutexUpgradeParams.Unlock()
 			//logical error -- reset the FSM
@@ -754,7 +770,7 @@
 		if err != nil {
 			logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
 				"device-id": oFsm.deviceID, "section absolute": oFsm.nextDownloadSectionsAbsolute, "error": err})
-			oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+			oFsm.abortOnOmciError(ctx, true)
 			return
 		}
 		oFsm.mutexUpgradeParams.Lock()
@@ -802,7 +818,6 @@
 	if pBaseFsm == nil {
 		logger.Errorw(ctx, "EndSwDl abort: BaseFsm invalid", log.Fields{"device-id": oFsm.deviceID})
 		oFsm.mutexUpgradeParams.Lock()
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR
 		oFsm.mutexUpgradeParams.Unlock()
 		// Can't call FSM Event directly, decoupling it
@@ -814,11 +829,10 @@
 	err := oFsm.pOmciCC.SendEndSoftwareDownload(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
 		oFsm.PAdaptFsm.CommChan, oFsm.InactiveImageMeID, oFsm.origImageLength, oFsm.imageCRC)
 
-	oFsm.isEndSwDlOpen = false // also to be reset in case of OMCI error, as further send attempts would not make sense
 	if err != nil {
 		logger.Errorw(ctx, "EndSwDl abort: can't send section", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 	// go waiting for the EndSwDLResponse and check, if the ONU is ready for activation
@@ -841,7 +855,7 @@
 			return
 		}
 		oFsm.mutexUpgradeParams.Lock()
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.isEndSwDlOpen = false                                         //no need to additionally request abort of download (already finished)
 		oFsm.volthaDownloadReason = voltha.ImageState_IMAGE_REFUSED_BY_ONU //something like 'END_DOWNLOAD_TIMEOUT' would be better (proto)
 		oFsm.mutexUpgradeParams.Unlock()
 		go func(a_pAFsm *cmn.AdapterFsm) {
@@ -870,6 +884,7 @@
 		return
 	case success := <-oFsm.chReceiveExpectedResponse:
 		logger.Debugw(ctx, "WaitEndDl stop  wait timer", log.Fields{"device-id": oFsm.deviceID})
+		oFsm.isEndSwDlOpen = false //no request to abort of download (already finished or immediate abort)
 		pBaseFsm := oFsm.PAdaptFsm
 		if pBaseFsm == nil {
 			logger.Errorw(ctx, "WaitEndDl abort: BaseFsm invalid", log.Fields{
@@ -900,7 +915,7 @@
 			return
 		}
 		//timer was aborted
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 }
@@ -915,7 +930,7 @@
 	if err != nil {
 		logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
 			log.Fields{"device-id": oFsm.deviceID, "Error": err})
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 	oFsm.pLastTxMeInstance = meInstance
@@ -930,10 +945,11 @@
 	if err != nil {
 		logger.Errorw(ctx, "ActivateSw abort: can't send activate frame", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 	oFsm.mutexUpgradeParams.Lock()
+	oFsm.upgradePhase = cUpgradeActivating //start of image activation for ONU
 	oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING
 	oFsm.mutexUpgradeParams.Unlock()
 }
@@ -951,13 +967,14 @@
 			logger.Infow(ctx, "OnuUpgradeFsm commit SW", log.Fields{
 				"device-id": oFsm.deviceID, "me-id": inactiveImageID}) //more efficient activeImageID with above check
 			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTING
+			oFsm.upgradePhase = cUpgradeCommitting //start of image commitment for ONU
 			oFsm.mutexUpgradeParams.Unlock()
 			err := oFsm.pOmciCC.SendCommitSoftware(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
 				oFsm.PAdaptFsm.CommChan, inactiveImageID) //more efficient activeImageID with above check
 			if err != nil {
 				logger.Errorw(ctx, "CommitSw abort: can't send commit sw frame", log.Fields{
 					"device-id": oFsm.deviceID, "error": err})
-				oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+				oFsm.abortOnOmciError(ctx, true)
 				return
 			}
 			return
@@ -971,9 +988,7 @@
 	}
 	oFsm.mutexUpgradeParams.Lock()
 	oFsm.conditionalCancelRequested = false //any lingering conditional cancelRequest is superseded by this error
-	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 	oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
-	oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
 	oFsm.mutexUpgradeParams.Unlock()
 	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
 	pBaseFsm := oFsm.PAdaptFsm
@@ -992,7 +1007,7 @@
 	if err != nil {
 		logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
 			log.Fields{"device-id": oFsm.deviceID, "Error": err})
-		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+		oFsm.abortOnOmciError(ctx, true)
 		return
 	}
 	oFsm.pLastTxMeInstance = meInstance
@@ -1001,13 +1016,7 @@
 func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "OnuUpgradeFsm resetting", log.Fields{"device-id": oFsm.deviceID})
 
-	// if the reset was conditionally requested
-	if oFsm.conditionalCancelRequested {
-		oFsm.mutexUpgradeParams.Lock()
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
-		oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
-		oFsm.mutexUpgradeParams.Unlock()
-	}
+	oFsm.stateUpdateOnReset(ctx)
 
 	// in case the download-to-ONU timer is still running - cancel it
 	//use non-blocking channel (to be independent from receiver state)
@@ -1020,6 +1029,12 @@
 	if pConfigUpgradeStateAFsm != nil {
 		var nextEvent string
 		if oFsm.isEndSwDlOpen {
+			if oFsm.repeatAbort {
+				oFsm.delayEndSwDl = true //run next abort with delay
+			} else { //initial request
+				oFsm.delayEndSwDl = false                 //run next abort with no delay
+				oFsm.waitCountEndSwDl = cWaitCountEndSwDl //init for possible repetitions
+			}
 			nextEvent = UpgradeEvAbortSwDownload
 		} else {
 			nextEvent = UpgradeEvRestart
@@ -1036,6 +1051,15 @@
 func (oFsm *OnuUpgradeFsm) enterAbortingDL(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "OnuUpgradeFsm aborting download to ONU", log.Fields{"device-id": oFsm.deviceID})
 
+	oFsm.mutexUpgradeParams.RLock()
+	if oFsm.delayEndSwDl {
+		oFsm.mutexUpgradeParams.RUnlock()
+		//give the ONU some time for image discard activities
+		time.Sleep(cOmciEndSwDlDelaySeconds * time.Second)
+	} else {
+		oFsm.mutexUpgradeParams.RUnlock()
+	}
+
 	pBaseFsm := oFsm.PAdaptFsm
 	if pBaseFsm == nil {
 		logger.Errorw(ctx, "OnuUpgradeFsm aborting download: BaseFsm invalid", log.Fields{"device-id": oFsm.deviceID})
@@ -1045,8 +1069,6 @@
 	err := oFsm.pOmciCC.SendEndSoftwareDownload(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
 		oFsm.PAdaptFsm.CommChan, oFsm.InactiveImageMeID, 0, 0xFFFFFFFF)
 
-	oFsm.isEndSwDlOpen = false // also to be reset in case of OMCI error, as further send attempts would not make sense
-
 	if err != nil {
 		logger.Errorw(ctx, "OnuUpgradeFsm aborting download: can't send EndSwDl request", log.Fields{"device-id": oFsm.deviceID})
 		// Can't call FSM Event directly, decoupling it
@@ -1066,15 +1088,58 @@
 			}
 		}(pBaseFsm)
 		return
-	case <-oFsm.chReceiveAbortEndSwDlResponse:
-		logger.Debug(ctx, "OnuUpgradeFsm aborting download: response received")
+	case response := <-oFsm.chReceiveAbortEndSwDlResponse:
+		logger.Debugw(ctx, "OnuUpgradeFsm aborting download: response received",
+			log.Fields{"device-id": oFsm.deviceID, "response": response})
+		//had to shift processing to separate function due to SCA complexity
+		if oFsm.abortingDlEvaluateResponse(ctx, pBaseFsm, response) {
+			return //event sent from function already
+		}
 		go func(a_pAFsm *cmn.AdapterFsm) {
 			if a_pAFsm != nil && a_pAFsm.PFsm != nil {
 				_ = a_pAFsm.PFsm.Event(UpgradeEvRestart)
 			}
 		}(pBaseFsm)
 		return
-	}
+	} //select
+}
+
+//abortingDlEvaluateResponse  waits for a channel indication with decision to proceed the FSM processing
+func (oFsm *OnuUpgradeFsm) abortingDlEvaluateResponse(ctx context.Context,
+	pBaseFsm *cmn.AdapterFsm, aResponseResult tEndSwDlResponseResult) bool {
+	switch aResponseResult {
+	case cEndSwDlResponseBusy: // indication for device busy, needs repetition
+		if oFsm.waitCountEndSwDl == 0 {
+			logger.Errorw(ctx, "aborting download: max limit of EndSwDl reached", log.Fields{
+				"device-id": oFsm.deviceID})
+			go func(a_pAFsm *cmn.AdapterFsm) {
+				if a_pAFsm != nil && a_pAFsm.PFsm != nil {
+					_ = a_pAFsm.PFsm.Event(UpgradeEvRestart) //give up and let FSM terminate
+				}
+			}(pBaseFsm)
+		} else {
+			logger.Debugw(ctx, "aborting download: re-trigger sending abort SwDl", log.Fields{
+				"device-id": oFsm.deviceID, "counter": oFsm.waitCountEndSwDl})
+			oFsm.waitCountEndSwDl--
+			oFsm.repeatAbort = true //repeated request in next round
+			go func(a_pAFsm *cmn.AdapterFsm) {
+				if a_pAFsm != nil && a_pAFsm.PFsm != nil {
+					_ = a_pAFsm.PFsm.Event(UpgradeEvReset) //which then re-triggers sending AbortSwDL
+				}
+			}(pBaseFsm)
+		}
+		return true
+	case cEndSwDlResponseSuccess: // indication for success response
+		logger.Infow(ctx, "aborting download: success response, terminating FSM", log.Fields{
+			"device-id": oFsm.deviceID})
+	case cEndSwDlResponseAbort: // indication for request to abort waiting for response
+		logger.Infow(ctx, "aborting download: request to abort waiting, terminating FSM", log.Fields{
+			"device-id": oFsm.deviceID})
+	default:
+		logger.Errorw(ctx, "aborting download: unknown channel indication, terminating FSM", log.Fields{
+			"device-id": oFsm.deviceID})
+	} //switch
+	return false
 }
 
 func (oFsm *OnuUpgradeFsm) enterRestarting(ctx context.Context, e *fsm.Event) {
@@ -1126,7 +1191,7 @@
 		if !ok {
 			logger.Info(ctx, "OnuUpgradeFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
-			oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+			oFsm.abortOnOmciError(ctx, true)
 			break loop
 		}
 		logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
@@ -1150,7 +1215,6 @@
 	logger.Infow(ctx, "End OnuUpgradeFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
 }
 
-//nolint: gocyclo
 func (oFsm *OnuUpgradeFsm) handleOmciOnuUpgradeMessage(ctx context.Context, msg cmn.OmciMessage) {
 	logger.Debugw(ctx, "Rx OMCI OnuUpgradeFsm Msg", log.Fields{"device-id": oFsm.deviceID,
 		"msgType": msg.OmciMsg.MessageType})
@@ -1158,196 +1222,17 @@
 	switch msg.OmciMsg.MessageType {
 	case omci.StartSoftwareDownloadResponseType:
 		{
-			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
-			if msgLayer == nil {
-				logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
-			if !msgOk {
-				logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
-				"device-id": oFsm.deviceID, "data-fields": msgObj})
-			if msgObj.Result != me.Success {
-				logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
-					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-
-			oFsm.mutexUpgradeParams.Lock()
-			if msgObj.EntityInstance == oFsm.InactiveImageMeID {
-				logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
-				if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
-					// also response WindowSize = 0 is a valid number for used Window size 1
-					logger.Debugw(ctx, "different StartSwDlResponse window size requested by ONU", log.Fields{
-						"acceptedOnuWindowSizeLimit": msgObj.WindowSize, "device-id": oFsm.deviceID})
-					oFsm.omciDownloadWindowSizeLimit = msgObj.WindowSize
-				}
-				oFsm.noOfWindows = oFsm.noOfSections / uint32(oFsm.omciDownloadWindowSizeLimit+1)
-				if oFsm.noOfSections%uint32(oFsm.omciDownloadWindowSizeLimit+1) > 0 {
-					oFsm.noOfWindows++
-				}
-				logger.Debugw(ctx, "OnuUpgradeFsm will use", log.Fields{
-					"windows": oFsm.noOfWindows, "sections": oFsm.noOfSections,
-					"at WindowSizeLimit": oFsm.omciDownloadWindowSizeLimit})
-				oFsm.nextDownloadSectionsAbsolute = 0
-				oFsm.nextDownloadSectionsWindow = 0
-				oFsm.nextDownloadWindow = 0
-
-				oFsm.mutexUpgradeParams.Unlock()
-				_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRxStartSwDownload)
-				return
-			}
-			oFsm.mutexUpgradeParams.Unlock()
-			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
-				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+			oFsm.handleRxStartSwDownloadResponse(ctx, msg)
 			return
 		} //StartSoftwareDownloadResponseType
 	case omci.DownloadSectionResponseType:
 		{
-			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
-			if msgLayer == nil {
-				logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
-					log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
-			if !msgOk {
-				logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
-				"device-id": oFsm.deviceID, "data-fields": msgObj})
-			if msgObj.Result != me.Success {
-				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
-					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			oFsm.mutexUpgradeParams.Lock()
-			if msgObj.EntityInstance == oFsm.InactiveImageMeID {
-				sectionNumber := msgObj.SectionNumber
-				logger.Infow(ctx, "DlSectionResponse received", log.Fields{
-					"window section-number": sectionNumber, "window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
-
-				oFsm.nextDownloadWindow++
-				if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
-					if sectionNumber != oFsm.omciDownloadWindowSizeLast {
-						logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error last window - later: repeat window once?", //TODO!!!
-							log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
-								"expected section": oFsm.omciDownloadWindowSizeLast})
-						oFsm.mutexUpgradeParams.Unlock()
-						oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-						return
-					}
-					oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
-					//CRC computation for all data bytes of the file
-					imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //store internal for multiple usage
-					//revert the retrieved CRC Byte Order (seems not to deliver NetworkByteOrder)
-					var byteSlice []byte = make([]byte, 4)
-					binary.LittleEndian.PutUint32(byteSlice, uint32(imageCRC))
-					oFsm.imageCRC = binary.BigEndian.Uint32(byteSlice)
-					oFsm.mutexUpgradeParams.Unlock()
-					_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvEndSwDownload)
-					return
-				}
-				if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
-					logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
-						log.Fields{"device-id": oFsm.deviceID, "actual-section": sectionNumber,
-							"expected section": oFsm.omciDownloadWindowSizeLimit})
-					oFsm.mutexUpgradeParams.Unlock()
-					oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-					return
-				}
-				oFsm.nextDownloadSectionsWindow = 0
-				oFsm.mutexUpgradeParams.Unlock()
-				_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvContinueNextWindow)
-				return
-			}
-			oFsm.mutexUpgradeParams.Unlock()
-			logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
-				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+			oFsm.handleRxSwSectionResponse(ctx, msg)
 			return
 		} //DownloadSectionResponseType
 	case omci.EndSoftwareDownloadResponseType:
 		{
-			if oFsm.PAdaptFsm.PFsm.Is(UpgradeStAbortingDL) {
-				// calling FSM events in background to avoid blocking of the caller
-				go func(aPAFsm *cmn.AdapterFsm) {
-					oFsm.chReceiveAbortEndSwDlResponse <- true
-				}(oFsm.PAdaptFsm)
-				return
-			}
-			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeEndSoftwareDownloadResponse)
-			if msgLayer == nil {
-				logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
-			if !msgOk {
-				logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
-				"device-id": oFsm.deviceID, "data-fields": msgObj})
-			if msgObj.Result != me.Success {
-				if msgObj.Result == me.DeviceBusy {
-					//ONU indicates it is still processing the image - let the FSM just wait and then repeat the request
-					logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse busy: waiting before sending new request", log.Fields{
-						"device-id": oFsm.deviceID})
-					return
-				}
-				logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
-					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
-				return
-			}
-			oFsm.mutexUpgradeParams.Lock()
-			if msgObj.EntityInstance == oFsm.InactiveImageMeID {
-				//EndSwDownloadSuccess is used to indicate 'DOWNLOAD_SUCCEEDED'
-				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
-				if !oFsm.useAPIVersion43 {
-					//in the older API version the image version check was not possible
-					//  - assume new loaded image as valid-inactive immediately
-					oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
-					oFsm.mutexUpgradeParams.Unlock()
-					//use non-blocking channel (to be independent from receiver state)
-					select {
-					//use non-blocking channel to indicate that the download to ONU was successful
-					case oFsm.chOnuDlReady <- true:
-					default:
-					}
-				} else {
-					oFsm.mutexUpgradeParams.Unlock()
-				}
-				logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
-				//use non-blocking channel to let the FSM proceed from the waitState
-				select {
-				case oFsm.chReceiveExpectedResponse <- true:
-				default:
-				}
-				return
-			}
-			oFsm.mutexUpgradeParams.Unlock()
-			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
-				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+			oFsm.handleRxEndSwDownloadResponse(ctx, msg)
 			return
 		} //EndSoftwareDownloadResponseType
 	case omci.ActivateSoftwareResponseType:
@@ -1356,14 +1241,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
@@ -1371,7 +1256,7 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			oFsm.mutexUpgradeParams.Lock()
@@ -1390,7 +1275,7 @@
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+			oFsm.abortOnOmciError(ctx, false)
 			return
 		} //ActivateSoftwareResponseType
 	case omci.CommitSoftwareResponseType:
@@ -1399,20 +1284,20 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for CommitResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.CommitSoftwareResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for CommitResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+				oFsm.abortOnOmciError(ctx, false)
 				return
 			}
 			oFsm.mutexUpgradeParams.RLock()
@@ -1426,167 +1311,12 @@
 			oFsm.mutexUpgradeParams.RUnlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse  wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+			oFsm.abortOnOmciError(ctx, false)
 			return
 		} //CommitSoftwareResponseType
 	case omci.GetResponseType:
 		{
-			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
-			if msgLayer == nil {
-				logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
-				return
-			}
-			msgObj, msgOk := msgLayer.(*omci.GetResponse)
-			if !msgOk {
-				logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
-					log.Fields{"device-id": oFsm.deviceID})
-				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
-				return
-			}
-			logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
-				"device-id": oFsm.deviceID, "data-fields": msgObj})
-			if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
-				msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
-				if msgObj.Result != me.Success {
-					logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
-						log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-					oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
-					return
-				}
-			} else {
-				logger.Warnw(ctx, "OnuUpgradeFsm SwImage unexpected Entity GetResponse data - ignore",
-					log.Fields{"device-id": oFsm.deviceID})
-				return
-			}
-
-			meAttributes := msgObj.Attributes
-			imageIsCommitted := meAttributes["IsCommitted"].(uint8)
-			imageIsActive := meAttributes["IsActive"].(uint8)
-			imageVersion := cmn.TrimStringFromMeOctet(meAttributes["Version"])
-			logger.Debugw(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
-				log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
-					"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
-
-			if oFsm.PAdaptFsm.PFsm.Current() == UpgradeStCheckImageName {
-				//image name check after EndSwDownload, this state (and block) can only be taken if APIVersion43 is used
-				oFsm.mutexUpgradeParams.Lock()
-				if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsInactive &&
-					imageIsCommitted == cmn.SwIsUncommitted {
-					if imageVersion != oFsm.imageVersion {
-						//new stored inactive version indicated on OMCI from ONU is not the expected version
-						logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse version indication not matching requested upgrade",
-							log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
-								"onu-version": imageVersion, "expected-version": oFsm.imageVersion})
-						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED         //not the expected image was downloaded
-						oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
-						oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN              //something like 'DOWNLOADED' would be better - proto def
-						oFsm.mutexUpgradeParams.Unlock()
-						//stop the running ONU download timer
-						//use non-blocking channel (to be independent from receiver state)
-						select {
-						//use channel to indicate that the download response waiting shall be aborted for this device (channel)
-						case oFsm.chOnuDlReady <- false:
-						default:
-						}
-						// TODO!!!: error treatment?
-						//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
-						_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
-						return
-					}
-					//with APIVersion43 this is the point to consider the newly loaded image as valid (and inactive)
-					oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
-					//store the new inactive version to onuSwImageIndications (to keep them in sync)
-					oFsm.pDevEntry.ModifySwImageInactiveVersion(ctx, oFsm.imageVersion)
-					//proceed within upgrade FSM
-					if oFsm.activateImage {
-						//immediate activation requested
-						oFsm.mutexUpgradeParams.Unlock()
-						logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, continue with activation",
-							log.Fields{"device-id": oFsm.deviceID})
-						_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRequestActivate)
-					} else {
-						//have to wait on explicit activation request
-						// but a previously requested download activity (without activation) was successful here
-						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
-						oFsm.mutexUpgradeParams.Unlock()
-						logger.Infow(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, wait for activate request",
-							log.Fields{"device-id": oFsm.deviceID})
-						_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvWaitForActivate)
-					}
-					//use non-blocking channel (to be independent from receiver state)
-					select {
-					//use non-blocking channel to indicate that the download to ONU was successful
-					case oFsm.chOnuDlReady <- true:
-					default:
-					}
-					return
-				}
-				//not the expected image/image state
-				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
-				oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
-				oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //real image state not known
-				oFsm.mutexUpgradeParams.Unlock()
-				logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
-					log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-				// TODO!!!: error treatment?
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by ONU state indication)?
-				_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
-				return
-			}
-
-			//assumed only relevant state here is UpgradeStCheckCommitted
-			oFsm.mutexUpgradeParams.Lock()
-			oFsm.conditionalCancelRequested = false //getting here any set (conditional) cancelRequest is not relevant anymore
-			if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsActive {
-				//a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
-				//  indicated in the download image version string (version must be part of the image content itself)
-				//  so checking that might be quite unreliable
-				//but with new API this was changed, assumption is that omci image version is known at download request and exactly that is used
-				//  in all the API references, so it can and should be checked here now
-				if oFsm.useAPIVersion43 {
-					if imageVersion != oFsm.imageVersion {
-						//new active version indicated on OMCI from ONU is not the expected version
-						logger.Errorw(ctx, "OnuUpgradeFsm image-version not matching the requested upgrade",
-							log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
-								"onu-version": imageVersion, "expected-version": oFsm.imageVersion})
-						// TODO!!!: error treatment?
-						//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
-						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED         //not the expected image was committed
-						oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
-						oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN              //expected image not known
-						oFsm.mutexUpgradeParams.Unlock()
-						_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
-						return
-					}
-					logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU",
-						log.Fields{"device-id": oFsm.deviceID})
-				}
-				if imageIsCommitted == cmn.SwIsCommitted {
-					oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
-					oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
-					//store the new commit flag to onuSwImageIndications (to keep them in sync)
-					oFsm.pDevEntry.ModifySwImageActiveCommit(ctx, imageIsCommitted)
-					logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
-					//deviceProcStatusUpdate not used anymore,
-					// replaced by transferring the last (more) upgrade state information within RemoveOnuUpgradeFsm
-					oFsm.mutexUpgradeParams.Unlock()
-					//releasing the upgrade FSM on success
-					_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
-					return
-				}
-				//if not committed, abort upgrade as failed. There is no implementation here that would trigger this test again
-			}
-			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
-			oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
-			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
-			oFsm.mutexUpgradeParams.Unlock()
-			logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
-				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: error treatment?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+			oFsm.handleRxSwGetResponse(ctx, msg)
 			return
 		} //GetResponseType
 	default:
@@ -1598,17 +1328,379 @@
 	}
 }
 
-//abortOnOmciError aborts the upgrade processing with OMCI_TRANSFER_ERROR indication
-func (oFsm *OnuUpgradeFsm) abortOnOmciError(ctx context.Context, aAsync bool,
-	aImageState voltha.ImageState_ImageActivationState) {
+func (oFsm *OnuUpgradeFsm) handleRxStartSwDownloadResponse(ctx context.Context, msg cmn.OmciMessage) {
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
+	if msgLayer == nil {
+		logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
+	if !msgOk {
+		logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
+		"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
+			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+
+	oFsm.mutexUpgradeParams.Lock()
+	if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+		logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+		if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
+			// also response WindowSize = 0 is a valid number for used Window size 1
+			logger.Debugw(ctx, "different StartSwDlResponse window size requested by ONU", log.Fields{
+				"acceptedOnuWindowSizeLimit": msgObj.WindowSize, "device-id": oFsm.deviceID})
+			oFsm.omciDownloadWindowSizeLimit = msgObj.WindowSize
+		}
+		oFsm.noOfWindows = oFsm.noOfSections / uint32(oFsm.omciDownloadWindowSizeLimit+1)
+		if oFsm.noOfSections%uint32(oFsm.omciDownloadWindowSizeLimit+1) > 0 {
+			oFsm.noOfWindows++
+		}
+		logger.Debugw(ctx, "OnuUpgradeFsm will use", log.Fields{
+			"windows": oFsm.noOfWindows, "sections": oFsm.noOfSections,
+			"at WindowSizeLimit": oFsm.omciDownloadWindowSizeLimit})
+		oFsm.nextDownloadSectionsAbsolute = 0
+		oFsm.nextDownloadSectionsWindow = 0
+		oFsm.nextDownloadWindow = 0
+
+		oFsm.mutexUpgradeParams.Unlock()
+		_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRxStartSwDownload)
+		return
+	}
+	oFsm.mutexUpgradeParams.Unlock()
+	logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
+		log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+	oFsm.abortOnOmciError(ctx, false)
+} //handleRxStartSwDownloadResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxSwSectionResponse(ctx context.Context, msg cmn.OmciMessage) {
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
+	if msgLayer == nil {
+		logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
+			log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
+	if !msgOk {
+		logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
+		"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
+			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	oFsm.mutexUpgradeParams.Lock()
+	if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+		sectionNumber := msgObj.SectionNumber
+		logger.Infow(ctx, "DlSectionResponse received", log.Fields{
+			"window section-number": sectionNumber, "window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
+
+		oFsm.nextDownloadWindow++
+		if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
+			if sectionNumber != oFsm.omciDownloadWindowSizeLast {
+				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error last window - later: repeat window once?", //TODO!!!
+					log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
+						"expected section": oFsm.omciDownloadWindowSizeLast})
+				oFsm.mutexUpgradeParams.Unlock()
+				oFsm.abortOnOmciError(ctx, false)
+				return
+			}
+			oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
+			//CRC computation for all data bytes of the file
+			imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //store internal for multiple usage
+			//revert the retrieved CRC Byte Order (seems not to deliver NetworkByteOrder)
+			var byteSlice []byte = make([]byte, 4)
+			binary.LittleEndian.PutUint32(byteSlice, uint32(imageCRC))
+			oFsm.imageCRC = binary.BigEndian.Uint32(byteSlice)
+			oFsm.mutexUpgradeParams.Unlock()
+			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvEndSwDownload)
+			return
+		}
+		if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
+			logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
+				log.Fields{"device-id": oFsm.deviceID, "actual-section": sectionNumber,
+					"expected section": oFsm.omciDownloadWindowSizeLimit})
+			oFsm.mutexUpgradeParams.Unlock()
+			oFsm.abortOnOmciError(ctx, false)
+			return
+		}
+		oFsm.nextDownloadSectionsWindow = 0
+		oFsm.mutexUpgradeParams.Unlock()
+		_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvContinueNextWindow)
+		return
+	}
+	oFsm.mutexUpgradeParams.Unlock()
+	logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
+		log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+	oFsm.abortOnOmciError(ctx, false)
+} //handleRxSwSectionResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxEndSwDownloadResponse(ctx context.Context, msg cmn.OmciMessage) {
+	inAbortingState := oFsm.PAdaptFsm.PFsm.Is(UpgradeStAbortingDL)
+
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeEndSoftwareDownloadResponse)
+	if msgLayer == nil {
+		logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		if !inAbortingState {
+			oFsm.abortOnOmciError(ctx, false)
+		} //else using error log and wait for another response or 'aborting' state timeout
+		return
+	}
+	msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
+	if !msgOk {
+		logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		if !inAbortingState {
+			oFsm.abortOnOmciError(ctx, false)
+		} //else using error log and wait for another response or 'aborting' state timeout
+		return
+	}
+	logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
+		"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		if msgObj.Result == me.DeviceBusy {
+			//ONU indicates it is still processing the image - let the FSM just wait and then repeat the request
+			logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse busy: waiting before sending new request", log.Fields{
+				"device-id": oFsm.deviceID})
+			if inAbortingState {
+				//if the EndSwDl was requested from state AbortingDL then use channel to indicate ONU busy/repeat indication
+				oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseBusy //repeat abort request
+			}
+			oFsm.mutexUpgradeParams.Lock()
+			oFsm.downloadReasonCached = oFsm.volthaDownloadReason //copy for later reconstruction
+			oFsm.volthaDownloadReason = voltha.ImageState_DEVICE_BUSY
+			oFsm.mutexUpgradeParams.Unlock()
+			return
+		}
+		logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
+			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+		if inAbortingState {
+			//if the EndSwDl was requested from state AbortingDL and response is error indication
+			// that would be quite strange ONU behavior, no resolution from OnuAdapter, just let the FSM go on to disabled
+			oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseAbort //error indication to abort waiting on EndDownloadResponse
+		} //else using error log and wait for another response or 'aborting' state timeout
+		return
+	}
+	oFsm.mutexUpgradeParams.Lock()
+	if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+		logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+		if oFsm.volthaDownloadReason == voltha.ImageState_DEVICE_BUSY { //was temporary on busy
+			oFsm.volthaDownloadReason = oFsm.downloadReasonCached //recapture from mirror
+		}
+		if inAbortingState {
+			oFsm.mutexUpgradeParams.Unlock()
+			//if the EndSwDl was requested from state AbortingDL then use channel to indicate abort acceptance
+			oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseSuccess //success
+			return
+		}
+		if !oFsm.useAPIVersion43 {
+			//in the older API version the image version check was not possible
+			//  - assume new loaded image as valid-inactive immediately
+			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+			oFsm.mutexUpgradeParams.Unlock()
+			//use non-blocking channel (to be independent from receiver state)
+			select {
+			//use non-blocking channel to indicate that the download to ONU was successful
+			case oFsm.chOnuDlReady <- true:
+			default:
+			}
+		} else {
+			oFsm.mutexUpgradeParams.Unlock()
+		}
+		//use asynchronous channel sending to let the FSM proceed
+		select {
+		case oFsm.chReceiveExpectedResponse <- true:
+		default:
+		}
+		return
+	}
+	oFsm.mutexUpgradeParams.Unlock()
+	logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: ignoring",
+		log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+	// no state abort in case of unexpected ImageId, just keep waiting for the correct one
+} //handleRxEndSwDownloadResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxSwGetResponse(ctx context.Context, msg cmn.OmciMessage) {
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
+	if msgLayer == nil {
+		logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	msgObj, msgOk := msgLayer.(*omci.GetResponse)
+	if !msgOk {
+		logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		oFsm.abortOnOmciError(ctx, false)
+		return
+	}
+	logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
+		"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+		if msgObj.Result != me.Success {
+			logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
+				log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+			oFsm.abortOnOmciError(ctx, false)
+			return
+		}
+	} else {
+		logger.Warnw(ctx, "OnuUpgradeFsm SwImage unexpected Entity GetResponse data - ignore",
+			log.Fields{"device-id": oFsm.deviceID})
+		return
+	}
+
+	meAttributes := msgObj.Attributes
+	imageIsCommitted := meAttributes["IsCommitted"].(uint8)
+	imageIsActive := meAttributes["IsActive"].(uint8)
+	imageVersion := cmn.TrimStringFromMeOctet(meAttributes["Version"])
+	logger.Debugw(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
+		log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
+			"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
+
+	if oFsm.PAdaptFsm.PFsm.Current() == UpgradeStCheckImageName {
+		//image name check after EndSwDownload, this state (and block) can only be taken if APIVersion43 is used
+		oFsm.verifyOnuSwStatusAfterDownload(ctx, msgObj.EntityInstance, imageVersion, imageIsActive, imageIsCommitted)
+		return
+	}
+
+	//assumed only relevant state here is upgradeStCheckCommitted
+	oFsm.mutexUpgradeParams.Lock()
+	oFsm.conditionalCancelRequested = false //getting here any set (conditional) cancelRequest is not relevant anymore
+	if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsActive {
+		//a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
+		//  indicated in the download image version string (version must be part of the image content itself)
+		//  so checking that might be quite unreliable
+		//but with new API this was changed, assumption is that omci image version is known at download request and exactly that is used
+		//  in all the API references, so it can and should be checked here now
+		if oFsm.useAPIVersion43 {
+			if imageVersion != oFsm.imageVersion {
+				//new active version indicated on OMCI from ONU is not the expected version
+				logger.Errorw(ctx, "OnuUpgradeFsm image-version not matching the requested upgrade",
+					log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
+						"onu-version": imageVersion, "expected-version": oFsm.imageVersion})
+				// TODO!!!: error treatment?
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+				oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+				oFsm.mutexUpgradeParams.Unlock()
+				_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+				return
+			}
+			logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU",
+				log.Fields{"device-id": oFsm.deviceID})
+		}
+		if imageIsCommitted == cmn.SwIsCommitted {
+			oFsm.upgradePhase = cUpgradeCommitted
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
+			//store the new commit flag to onuSwImageIndications (to keep them in sync)
+			oFsm.pDevEntry.ModifySwImageActiveCommit(ctx, imageIsCommitted)
+			logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
+			//deviceProcStatusUpdate not used anymore,
+			// replaced by transferring the last (more) upgrade state information within removeOnuUpgradeFsm
+			oFsm.mutexUpgradeParams.Unlock()
+			//releasing the upgrade FSM on success
+			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+			return
+		}
+		//if not committed, abort upgrade as failed. There is no implementation here that would trigger this test again
+	}
+	oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+	oFsm.mutexUpgradeParams.Unlock()
+	logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+		log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+	// TODO!!!: error treatment?
+	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+	_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+} //handleRxSwGetResponse
+
+func (oFsm *OnuUpgradeFsm) verifyOnuSwStatusAfterDownload(ctx context.Context, aInstanceID uint16,
+	aImageVersion string, aImageIsActive uint8, aImageIsCommitted uint8) {
+	oFsm.mutexUpgradeParams.Lock()
+	if aInstanceID == oFsm.InactiveImageMeID && aImageIsActive == cmn.SwIsInactive &&
+		aImageIsCommitted == cmn.SwIsUncommitted {
+		if aImageVersion != oFsm.imageVersion {
+			//new stored inactive version indicated on OMCI from ONU is not the expected version
+			logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse version indication not matching requested upgrade",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": aInstanceID,
+					"onu-version": aImageVersion, "expected-version": oFsm.imageVersion})
+			//download state is set when entering the reset state
+			oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+			oFsm.mutexUpgradeParams.Unlock()
+			//stop the running ONU download timer
+			//use non-blocking channel (to be independent from receiver state)
+			select {
+			//use channel to indicate that the download response waiting shall be aborted for this device (channel)
+			case oFsm.chOnuDlReady <- false:
+			default:
+			}
+			// TODO!!!: error treatment?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+			return
+		}
+		//with APIVersion43 this is the point to consider the newly loaded image as valid (and inactive)
+		oFsm.upgradePhase = cUpgradeDownloaded
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+		//store the new inactive version to onuSwImageIndications (to keep them in sync)
+		oFsm.pDevEntry.ModifySwImageInactiveVersion(ctx, oFsm.imageVersion)
+		//proceed within upgrade FSM
+		if oFsm.activateImage {
+			//immediate activation requested
+			oFsm.mutexUpgradeParams.Unlock()
+			logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, continue with activation",
+				log.Fields{"device-id": oFsm.deviceID})
+			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRequestActivate)
+		} else {
+			//have to wait on explicit activation request
+			oFsm.mutexUpgradeParams.Unlock()
+			logger.Infow(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, wait for activate request",
+				log.Fields{"device-id": oFsm.deviceID})
+			_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvWaitForActivate)
+		}
+		//use non-blocking channel (to be independent from receiver state)
+		select {
+		//use non-blocking channel to indicate that the download to ONU was successful
+		case oFsm.chOnuDlReady <- true:
+		default:
+		}
+		return
+	}
+	//not the expected image/image state
+	oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+	oFsm.mutexUpgradeParams.Unlock()
+	logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+		log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": aInstanceID})
+	// TODO!!!: error treatment?
+	//TODO!!!: possibly send event information for aborted upgrade (aborted by ONU state indication)?
+	_ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+} //verifyOnuSwStatusAfterDownload
+
+//abortOnOmciError aborts the upgrade processing with evAbort
+//  asynchronous/synchronous based on parameter aAsync
+func (oFsm *OnuUpgradeFsm) abortOnOmciError(ctx context.Context, aAsync bool) {
 	oFsm.mutexUpgradeParams.Lock()
 	oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
-	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
 	oFsm.volthaDownloadReason = voltha.ImageState_OMCI_TRANSFER_ERROR
-	if aImageState != voltha.ImageState_IMAGE_UNKNOWN {
-		// update image state only in case some explicite state is given (otherwise the existing state is used)
-		oFsm.volthaImageState = aImageState
-	}
 	oFsm.mutexUpgradeParams.Unlock()
 	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
 	if oFsm.PAdaptFsm != nil {
@@ -1654,10 +1746,8 @@
 		oFsm.isWaitingForAdapterDlResponse = false
 		oFsm.mutexIsAwaitingAdapterDlResponse.Unlock()
 		oFsm.mutexUpgradeParams.Lock()
-		oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.conditionalCancelRequested = false                     //any conditional cancelRequest is superseded by this abortion
 		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'DOWNLOAD_TO_ADAPTER_TIMEOUT' would be better (proto)
-		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN     //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
 		oFsm.mutexUpgradeParams.Unlock()
 		//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
 		if oFsm.PAdaptFsm != nil && oFsm.PAdaptFsm.PFsm != nil {
@@ -1708,7 +1798,7 @@
 		logger.Warnw(ctx, "OnuUpgradeFsm Waiting-ONU-download timeout", log.Fields{
 			"for device-id": oFsm.deviceID, "image-id": oFsm.imageIdentifier, "timeout": downloadToOnuTimeout})
 		//the upgrade process has to be aborted
-		oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		oFsm.abortOnOmciError(ctx, false)
 		return
 
 	case success := <-aWaitChannel:
@@ -1723,3 +1813,40 @@
 		return
 	}
 }
+
+//stateUpdateOnReset writes the download and/or image state on entering the reset state according to FSM internal indications
+func (oFsm *OnuUpgradeFsm) stateUpdateOnReset(ctx context.Context) {
+	oFsm.mutexUpgradeParams.Lock()
+	defer oFsm.mutexUpgradeParams.Unlock()
+	if !oFsm.conditionalCancelRequested {
+		switch oFsm.upgradePhase {
+		case cUpgradeUndefined, cUpgradeDownloading: //coming from downloading
+			//make sure the download state is only changed in case the device has still been downloading
+			if oFsm.volthaDownloadReason == voltha.ImageState_CANCELLED_ON_REQUEST {
+				// indication for termination on request
+				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+			} else if oFsm.volthaDownloadReason != voltha.ImageState_NO_ERROR {
+				// indication for termination on failure
+				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+			}
+			//reset the image state from Downloading in this case
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
+		//in all other upgrade phases the last set download state remains valid
+		case cUpgradeActivating:
+			//reset the image state from Activating in this case
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATION_ABORTED
+		case cUpgradeCommitting: // indication for request to abort waiting for response
+			//reset the image state from Activating in this case
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
+			//default: in all other upgrade phases keep the last set imageState
+		} //switch
+	} else {
+		//when reaching reset state with conditional cancel that can only result from ONU related problems
+		// (mostly ONU down indication) - derived from resetFsms call
+		// and it can only be related to the downloading-to-ONU phase (no need to check that additionally)
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+		//reset the image state from Downloading in this case
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
+	}
+}