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/ONU_Upgrade_Notes.md b/ONU_Upgrade_Notes.md
index 61a42db..a7668ae 100644
--- a/ONU_Upgrade_Notes.md
+++ b/ONU_Upgrade_Notes.md
@@ -1,9 +1,9 @@
 # Notes on ONU upgrade procedures using the openonu-go adapter
 Openonu-go adapter supports the download and activation of new ONU software from some external http(s) server to the ONUs over the OMCI channel.
-There are three relevant voltctl (image) commands for the ONU upgrade procedure:
-- voltctl device onuimage [list](#images-list-on-the-Onu)
+These are the relevant voltctl (image) commands for the ONU upgrade procedure:
+- voltctl device onuimage [list](#images-list-on-the-onu)
 - voltctl device onuimage [status](#image-status-display)
-- voltctl device onuimage [download](#image-download-from-http(s)-server-to-the-Onu)
+- voltctl device onuimage [download](#image-download-from-http-server-to-the-onu)
 - voltctl device onuimage [activate](#image-activation-on-the-onu)
 - voltctl device onuimage [commit](#image-commit-on-the-onu)
 - voltctl device onuimage [abort](#image-activity-abort)
@@ -75,7 +75,7 @@
 In above example output the given states indicate that for image software-image.img the download first to the openonu-go adapter
 and then to the ONU was correctly done. The image is in the inactive ONU partition (not yet activated).
 
-## Image download from http(s) server to the Onu
+## Image download from http server to the Onu
 
 The syntax of the complete voltctl command is:
 ```
@@ -119,7 +119,7 @@
 voltctl device onuimage activate <image-version> <commit-on-success> <onu-device-ids>
 ```
 with:
-- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http(s)-server-to-the-OnuAdapter) and [activate](#image-activation-on-the-onu) command
+- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http-server-to-the-onu) or the real inactive image version of the ONU (as given in the [list](#images-list-on-the-onu) command)
 - `<commit-on-success>`: commits the image automatically if activation is successful.
 - `<onu-device-ids>`: set of devices on which to activate the given image.
 
@@ -149,7 +149,7 @@
 voltctl device onuimage commit <image-version> <onu-device-ids>
 ```
 with:
-- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http(s)-server-to-the-OnuAdapter) and [activate](#image-activation-on-the-onu) command
+- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http-server-to-the-onu) or [activate](#image-activation-on-the-onu) command or the real active-uncommitted image version of the ONU (as given in the [list](#images-list-on-the-onu) command)
 - `<onu-device-ids>`: set of devices on which to commit the given image.
 
 A sample output of this command is:
@@ -164,8 +164,7 @@
 The processing of the command can be verified by checking the `IMAGESTATE` in the initial output of the command and then
 in result of the above given image [status](#image-status-display) command.
 
-The result of this command in the [list](#images-list-on-the-onu) should be that the desired image is also printed on the
-active partition and its `IsCommitted` and `IsActive` flags are set to true.
+The result of this command can be verified using the [list](#images-list-on-the-onu) command which should indicate the requested image with `IsCommitted` and `IsActive` flags set to true.
 
 ## Image activity abort
 
@@ -174,8 +173,7 @@
 voltctl device onuimage abort <image-version> <onu-device-ids>
 ```
 with:
-- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http(s)-server-to-the-OnuAdapter)
-  [activate](#image-activation-on-the-onu) and [commit](#image-commit-on-the-onu) commands
+- `<image-version>`: version of the image, the same identifier as used in the [download](#image-download-from-http-server-to-the-onu), [activate](#image-activation-on-the-onu) or [commit](#image-commit-on-the-onu) commands
 - `<onu-device-ids>`: set of devices on which to abort image processing.
 
 A sample output of this command is:
@@ -191,4 +189,11 @@
 
 The processing of the command can be verified with above given image [status](#image-status-display) command,
 where the `IMAGESTATE` defines the progress of this activity.
-Image status directly on the ONU device can always be performed by the [list](#images-list-on-the-onu) command. 
+Image status directly on the ONU device can always be performed by the [list](#images-list-on-the-onu) command.
+
+## User interface upgrade progress verification
+
+The 'activity' commands [download](#image-download-from-http-server-to-the-onu), [activate](#image-activation-on-the-onu), [commit](#image-commit-on-the-onu) and [abort](#image-activity-abort) provide an immediate response for the ONU related image states. These states then indicate that either the requested activity has just started or some processing problem was immediately detected that denies the execution of the request. In case no immediate error was found the requested processing is internally (in the ONU adapter) continued. This makes it necessary to verify the progress of the activity using the [status](#image-status-display) command. On success or later failure detection according image state indications are given that can be verified in order to detect the end and the result of the activity.
+
+The PDF document [OnuUpgradeStatesOvw](docs/OnuUpgradeStatesOvw.pdf) gives on overview of the main image state transitions implemented in the ONU adapter and can be used as guideline for such user interface verification.
+In the end the [list](#images-list-on-the-onu) command should be used in any case to verify the real situation on the concerned ONU.
diff --git a/VERSION b/VERSION
index 38f77a6..09bf7ca 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.0.1
+2.0.1-dev232
diff --git a/docs/OnuUpgradeStatesOvw.pdf b/docs/OnuUpgradeStatesOvw.pdf
new file mode 100755
index 0000000..4022410
--- /dev/null
+++ b/docs/OnuUpgradeStatesOvw.pdf
Binary files differ
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 22f08f8..537533c 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -1315,28 +1315,25 @@
 	pDeviceImageState.ImageState.Version = aVersion
 	dh.lockUpgradeFsm.RLock()
 	if dh.pOnuUpradeFsm != nil {
-		if aVersion == dh.pOnuUpradeFsm.GetImageVersion(ctx) {
-			// so then we cancel the upgrade operation
-			// but before we still request the actual ImageState (which should not change with the cancellation)
-			pDeviceImageState.ImageState.ImageState = dh.pOnuUpradeFsm.GetSpecificImageState(ctx)
-			dh.lockUpgradeFsm.RUnlock()
-			pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
-			pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+		dh.lockUpgradeFsm.RUnlock()
+		// so then we cancel the upgrade operation
+		// but before we still request the actual upgrade states (which should not change with the cancellation)
+		pImageState := dh.pOnuUpradeFsm.GetImageStates(ctx, aImageIdentifier, aVersion)
+		pDeviceImageState.ImageState.DownloadState = pImageState.DownloadState
+		pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+		pDeviceImageState.ImageState.ImageState = pImageState.ImageState
+		if pImageState.DownloadState != voltha.ImageState_DOWNLOAD_UNKNOWN {
+			//so here the imageIdentifier or version equals to what is used in the upgrade FSM
 			dh.pOnuUpradeFsm.CancelProcessing(ctx, true, voltha.ImageState_CANCELLED_ON_REQUEST) //complete abort
-		} else { //nothing to cancel, states unknown
-			dh.lockUpgradeFsm.RUnlock()
-			pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
-			pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
-			pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
-		}
+		} //nothing to cancel (upgrade FSM for different image stays alive)
 	} else {
+		dh.lockUpgradeFsm.RUnlock()
 		// if no upgrade is ongoing, nothing is canceled and accordingly the states of the requested image are unknown
 		// reset also the dh handler LastUpgradeImageState (not relevant anymore/cleared)
 		(*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
 		(*dh.pLastUpgradeImageState).Reason = voltha.ImageState_NO_ERROR
 		(*dh.pLastUpgradeImageState).ImageState = voltha.ImageState_IMAGE_UNKNOWN
 		(*dh.pLastUpgradeImageState).Version = "" //reset to 'no (relevant) upgrade done' (like initial state)
-		dh.lockUpgradeFsm.RUnlock()
 		pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
 		pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
 		pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
@@ -2638,8 +2635,8 @@
 					return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM could not be started for device-id: %s", dh.device.Id))
 				}
 				/***** LockStateFSM started */
-				//reset the last stored upgrade states
-				(*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_STARTED //already with updated state
+				//reset the last stored upgrade states (which anyway should be don't care as long as the newly created FSM exists)
+				(*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
 				(*dh.pLastUpgradeImageState).Reason = voltha.ImageState_NO_ERROR
 				(*dh.pLastUpgradeImageState).ImageState = voltha.ImageState_IMAGE_UNKNOWN
 				logger.Debugw(ctx, "OnuSwUpgradeFSM started", log.Fields{
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)
+	}
+}