VOL-3052 Onu Software preliminary upgrade test from Adapter to ONU, version 1.2.5-dev168

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I5f48645fa8b392c2c79f13cf8fd0d2369bfd5ca5
diff --git a/go.mod b/go.mod
index cb9b640..6cd9f23 100644
--- a/go.mod
+++ b/go.mod
@@ -3,14 +3,15 @@
 go 1.13
 
 require (
+	github.com/boguslaw-wojcik/crc32a v1.0.0
 	github.com/cevaris/ordered_map v0.0.0-20190319150403-3adeae072e73
 	github.com/gogo/protobuf v1.3.1
 	github.com/golang/protobuf v1.4.2
 	github.com/google/gopacket v1.1.17
 	github.com/looplab/fsm v0.1.0
 	github.com/opencord/omci-lib-go v0.15.0
-	github.com/opencord/voltha-lib-go/v4 v4.0.6
-	github.com/opencord/voltha-protos/v4 v4.0.11
+	github.com/opencord/voltha-lib-go/v4 v4.0.8
+	github.com/opencord/voltha-protos/v4 v4.0.12
 	github.com/stretchr/testify v1.6.1
 	google.golang.org/grpc v1.25.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 082f15b..d28d98f 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,8 @@
 github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/boguslaw-wojcik/crc32a v1.0.0 h1:rZUcnG4WkADJBW8tmb5ZWFN30w/mHV8+/hzM66X2ptQ=
+github.com/boguslaw-wojcik/crc32a v1.0.0/go.mod h1:BnG1x2VM7pNqIjOAHQKMu4NZ0Rn7cCxr+BmuXIbNOhM=
 github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d/go.mod h1:f1iKL6ZhUWvbk7PdWVmOaak10o86cqMUYEmn1CZNGEI=
 github.com/bsm/sarama-cluster v2.1.15+incompatible h1:RkV6WiNRnqEEbp81druK8zYhmnIgdOjqSVi0+9Cnl2A=
 github.com/bsm/sarama-cluster v2.1.15+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM=
@@ -219,12 +221,10 @@
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/opencord/omci-lib-go v0.15.0 h1:ADbDnHOm+XwOZ8CwRY0XmVnFXl/VIdygIdh3iZkbk6E=
 github.com/opencord/omci-lib-go v0.15.0/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
-github.com/opencord/voltha-lib-go/v4 v4.0.6 h1:Mc/bkYDR3YcpWPeW35ju9h3sO2cGByz8XM0ik5ikJkc=
-github.com/opencord/voltha-lib-go/v4 v4.0.6/go.mod h1:8NFUZz/mp4OvRmilBRhkLOUrw4G01ruSAVdzQu2ivPc=
-github.com/opencord/voltha-protos/v4 v4.0.8 h1:/P9IYuWPTp/aabS5n1fakQgHCFNzKjW1JHw3TOLAfKE=
-github.com/opencord/voltha-protos/v4 v4.0.8/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
-github.com/opencord/voltha-protos/v4 v4.0.11 h1:pJMNvjVxmCPGEUVPSLgqvT9P2ei2J+8Z9KsHJru2MRI=
-github.com/opencord/voltha-protos/v4 v4.0.11/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
+github.com/opencord/voltha-lib-go/v4 v4.0.8 h1:QgcbvmTG917U89FdjchCckvLprETR3A8qnd4BInvRnA=
+github.com/opencord/voltha-lib-go/v4 v4.0.8/go.mod h1:n4QSYuNICFuQCQuTHf4N8Gh4ymOqPNbijqCD+sgSgJ4=
+github.com/opencord/voltha-protos/v4 v4.0.12 h1:x8drb8inaUByjVLFbXSiQwRTU//dfde0MKIHyKb1JMw=
+github.com/opencord/voltha-protos/v4 v4.0.12/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
 github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
diff --git a/internal/pkg/onuadaptercore/adapter_download_manager.go b/internal/pkg/onuadaptercore/adapter_download_manager.go
index cf3718e..aaaacd6 100644
--- a/internal/pkg/onuadaptercore/adapter_download_manager.go
+++ b/internal/pkg/onuadaptercore/adapter_download_manager.go
@@ -18,8 +18,9 @@
 package adaptercoreonu
 
 import (
+	"bufio"
 	"context"
-	//"errors"
+	"os"
 	"sync"
 
 	//"time"
@@ -41,6 +42,8 @@
 type adapterDownloadManager struct {
 	mutexDownloadImageDsc sync.RWMutex
 	downloadImageDscSlice []*voltha.ImageDownload
+	// maybe just for test purpose
+	arrayFileFragment [32]byte
 }
 
 //newAdapterDownloadManager constructor returns a new instance of a adapterDownloadManager
@@ -49,7 +52,6 @@
 	logger.Debug(ctx, "init-adapterDownloadManager")
 	var localDnldMgr adapterDownloadManager
 	localDnldMgr.downloadImageDscSlice = make([]*voltha.ImageDownload, 0)
-
 	return &localDnldMgr
 }
 
@@ -69,11 +71,133 @@
 	return false
 }
 
+//imageLocallyDownloaded returns true if the requested image already exists within the adapter
+func (dm *adapterDownloadManager) imageLocallyDownloaded(ctx context.Context, apImageDsc *voltha.ImageDownload) bool {
+	logger.Debugw(ctx, "checking if image is fully downloaded", log.Fields{"image-name": (*apImageDsc).Name})
+	dm.mutexDownloadImageDsc.RLock()
+	defer dm.mutexDownloadImageDsc.RUnlock()
+
+	for _, pDnldImgDsc := range dm.downloadImageDscSlice {
+		if (*pDnldImgDsc).Name == (*apImageDsc).Name {
+			//image found (by name)
+			if (*pDnldImgDsc).DownloadState == voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
+				logger.Debugw(ctx, "image has been fully downloaded", log.Fields{"image-name": (*apImageDsc).Name})
+				return true
+			}
+			logger.Debugw(ctx, "image not yet fully downloaded", log.Fields{"image-name": (*apImageDsc).Name})
+			return false
+		}
+	}
+	//image not found (by name)
+	logger.Errorw(ctx, "image does not exist", log.Fields{"image-name": (*apImageDsc).Name})
+	return false
+}
+
 //startDownload returns true if the download of the requested image could be started
 func (dm *adapterDownloadManager) startDownload(ctx context.Context, apImageDsc *voltha.ImageDownload) error {
 	logger.Warnw(ctx, "image download requested - but not yet processed", log.Fields{"image-name": apImageDsc.Name})
+	newImageDscPos := len(dm.downloadImageDscSlice)
+	dm.downloadImageDscSlice = append(dm.downloadImageDscSlice, apImageDsc)
+	dm.downloadImageDscSlice[newImageDscPos].DownloadState = voltha.ImageDownload_DOWNLOAD_STARTED
+	//just some basic test file simulation
+	go dm.writeFileToLFS(ctx, apImageDsc.Name, apImageDsc.LocalDir)
 	//return success to comfort the core processing during integration
 	return nil
 	// TODO!!: also verify error response behavior
 	//return fmt.Errorf("onuSwUpgrade not yet implemented")
 }
+
+//writeFileToLFS writes the downloaded file to the local file system
+func (dm *adapterDownloadManager) writeFileToLFS(ctx context.Context, aFileName string, aLocalPath string) {
+	// by now just a simulation to write a file with predefined 'variable' content
+	totalFileLength := 0
+	logger.Debugw(ctx, "Writing fixed size simulation file locally", log.Fields{
+		"image-name": aFileName, "image-path": aLocalPath})
+	file, err := os.Create(aLocalPath + "/" + aFileName)
+	if err == nil {
+		// write 32KB test file
+		for totalFileLength < 32*1024 {
+			if written, wrErr := file.Write(dm.getIncrementalSliceContent(ctx)); wrErr == nil {
+				totalFileLength += written
+			} else {
+				logger.Errorw(ctx, "Could not write to file", log.Fields{"create-error": wrErr})
+				break //stop writing
+			}
+		}
+	} else {
+		logger.Errorw(ctx, "Could not create file", log.Fields{"create-error": err})
+	}
+
+	fileStats, statsErr := file.Stat()
+	if err != nil {
+		logger.Errorw(ctx, "created file can't be accessed", log.Fields{"stat-error": statsErr})
+	}
+	logger.Debugw(ctx, "Written file size is", log.Fields{"length": fileStats.Size()})
+	//nolint:gosec,errcheck
+	file.Close()
+
+	for _, pDnldImgDsc := range dm.downloadImageDscSlice {
+		if (*pDnldImgDsc).Name == aFileName {
+			//image found (by name)
+			(*pDnldImgDsc).DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
+			return //can leave directly
+		}
+	}
+}
+
+//getImageBufferLen returns the length of the specified file in bytes (file size)
+func (dm *adapterDownloadManager) getImageBufferLen(ctx context.Context, aFileName string,
+	aLocalPath string) (int64, error) {
+	//maybe we can also use FileSize from dm.downloadImageDscSlice - future option?
+
+	//nolint:gosec
+	file, err := os.Open(aLocalPath + "/" + aFileName)
+	if err != nil {
+		return 0, err
+	}
+	//nolint:errcheck
+	defer file.Close()
+
+	stats, statsErr := file.Stat()
+	if statsErr != nil {
+		return 0, statsErr
+	}
+
+	return stats.Size(), nil
+}
+
+//getDownloadImageBuffer returns the content of the requested file as byte slice
+func (dm *adapterDownloadManager) getDownloadImageBuffer(ctx context.Context, aFileName string,
+	aLocalPath string) ([]byte, error) {
+	//nolint:gosec
+	file, err := os.Open(aLocalPath + "/" + aFileName)
+	if err != nil {
+		return nil, err
+	}
+	//nolint:errcheck
+	defer file.Close()
+
+	stats, statsErr := file.Stat()
+	if statsErr != nil {
+		return nil, statsErr
+	}
+
+	var size int64 = stats.Size()
+	bytes := make([]byte, size)
+
+	buffer := bufio.NewReader(file)
+	_, err = buffer.Read(bytes)
+
+	return bytes, err
+}
+
+//getIncrementalSliceContent returns a byte slice of incremented bytes of internal array (used for file emulation)
+// (used for file emulation)
+func (dm *adapterDownloadManager) getIncrementalSliceContent(ctx context.Context) []byte {
+	lastValue := dm.arrayFileFragment[len(dm.arrayFileFragment)-1]
+	for index := range dm.arrayFileFragment {
+		lastValue++
+		dm.arrayFileFragment[index] = lastValue
+	}
+	return dm.arrayFileFragment[:]
+}
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index c55afd3..27d04dc 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -19,7 +19,6 @@
 
 import (
 	"context"
-	"encoding/hex"
 	"errors"
 	"fmt"
 	"strconv"
@@ -102,6 +101,7 @@
 	cAniConfigFsm
 	cUniVlanConfigFsm
 	cL2PmFsm
+	cOnuUpgradeFsm
 )
 
 type omciIdleCheckStruct struct {
@@ -117,6 +117,7 @@
 	cAniConfigFsm:     {(*deviceHandler).isAniConfigFsmInOmciIdleState, cAniFsmIdleState},
 	cUniVlanConfigFsm: {(*deviceHandler).isUniVlanConfigFsmInOmciIdleState, cVlanFsmIdleState},
 	cL2PmFsm:          {(*deviceHandler).isFsmInOmciIdleStateDefault, cL2PmFsmIdleState},
+	cOnuUpgradeFsm:    {(*deviceHandler).isFsmInOmciIdleStateDefault, cOnuUpgradeFsmIdleState},
 }
 
 const (
@@ -203,6 +204,8 @@
 	mutexKvStoreContext        sync.Mutex
 	lockVlanConfig             sync.RWMutex
 	UniVlanConfigFsmMap        map[uint8]*UniVlanConfigFsm
+	lockUpgradeFsm             sync.RWMutex
+	pOnuUpradeFsm              *OnuUpgradeFsm
 	reconciling                bool
 	mutexReconcilingFlag       sync.RWMutex
 	chReconcilingFinished      chan bool //channel to indicate that reconciling has been finished
@@ -233,6 +236,7 @@
 	//TODO initialize the support classes.
 	dh.uniEntityMap = make(map[uint32]*onuUniPort)
 	dh.lockVlanConfig = sync.RWMutex{}
+	dh.lockUpgradeFsm = sync.RWMutex{}
 	dh.UniVlanConfigFsmMap = make(map[uint8]*UniVlanConfigFsm)
 	dh.reconciling = false
 	dh.chReconcilingFinished = make(chan bool)
@@ -319,10 +323,12 @@
 		return err
 	}
 
+	/* msg print moved symmetrically to omci_cc, if wanted here as additional debug, than perhaps only based on additional debug setting!
 	//assuming omci message content is hex coded!
 	// with restricted output of 16(?) bytes would be ...omciMsg.Message[:16]
 	logger.Debugw(ctx, "inter-adapter-recv-omci", log.Fields{
 		"device-id": dh.deviceID, "RxOmciMessage": hex.EncodeToString(omciMsg.Message)})
+	*/
 	pDevEntry := dh.getOnuDeviceEntry(ctx, true)
 	if pDevEntry != nil {
 		if pDevEntry.PDevOmciCC != nil {
@@ -965,11 +971,47 @@
 }
 
 //doOnuSwUpgrade initiates the SW download transfer to the ONU and on success activates the (inactive) image
-func (dh *deviceHandler) doOnuSwUpgrade(ctx context.Context, apImageDsc *voltha.ImageDownload) error {
-	logger.Warnw(ctx, "onuSwUpgrade not yet implemented in deviceHandler", log.Fields{
+func (dh *deviceHandler) doOnuSwUpgrade(ctx context.Context, apImageDsc *voltha.ImageDownload,
+	apDownloadManager *adapterDownloadManager) error {
+	logger.Debugw(ctx, "onuSwUpgrade requested", log.Fields{
 		"device-id": dh.deviceID, "image-name": (*apImageDsc).Name})
-	//return success to comfort the core processing during integration
-	return nil
+
+	var err error
+	if dh.ReadyForSpecificOmciConfig {
+		dh.lockUpgradeFsm.Lock()
+		defer dh.lockUpgradeFsm.Unlock()
+		if dh.pOnuUpradeFsm == nil {
+			err = dh.createOnuUpgradeFsm(ctx, OmciOnuSwUpgradeDone)
+			if err == nil {
+				if err = dh.pOnuUpradeFsm.SetDownloadParams(ctx, apImageDsc, apDownloadManager); err != nil {
+					logger.Errorw(ctx, "onu upgrade fsm could not set parameters", log.Fields{
+						"device-id": dh.deviceID, "error": err})
+				}
+			} else {
+				logger.Errorw(ctx, "onu upgrade fsm could not be created", log.Fields{
+					"device-id": dh.deviceID, "error": err})
+			}
+		} else { //OnuSw upgrade already running - restart (with possible abort of running)
+			logger.Debugw(ctx, "Onu SW upgrade already running - abort", log.Fields{"device-id": dh.deviceID})
+			pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
+			if pUpgradeStatemachine != nil {
+				if err = pUpgradeStatemachine.Event(upgradeEvAbort); err != nil {
+					logger.Errorw(ctx, "onu upgrade fsm could not abort a running processing", log.Fields{
+						"device-id": dh.deviceID, "error": err})
+				}
+				err = fmt.Errorf("aborted Onu SW upgrade but not automatically started, try again, device-id: %s", dh.deviceID)
+				//TODO!!!: wait for 'ready' to start and configure - see above SetDownloadParams()
+				// for now a second start of download should work again
+			} else { //should never occur
+				logger.Errorw(ctx, "onu upgrade fsm inconsistent setup", log.Fields{
+					"device-id": dh.deviceID})
+				err = fmt.Errorf("onu upgrade fsm inconsistent setup, baseFsm invalid for device-id: %s", dh.deviceID)
+			}
+		}
+	} else {
+		logger.Errorw(ctx, "Start Onu SW upgrade rejected: no active OMCI connection", log.Fields{"device-id": dh.deviceID})
+	}
+	return err
 }
 
 //  deviceHandler methods that implement the adapters interface requests## end #########
@@ -1601,6 +1643,15 @@
 		dh.stopAlarmManager <- true
 	}
 
+	//reset a possibly running upgrade FSM
+	// specific here: If the FSM is in upgradeStWaitForCommit, it is left there for possibly later commit
+	// this possibly also refers later to (not yet existing) upgradeStWaitForActivate (with ctl API changes)
+	dh.lockUpgradeFsm.RLock()
+	if dh.pOnuUpradeFsm != nil {
+		_ = dh.pOnuUpradeFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
+	}
+	dh.lockUpgradeFsm.RUnlock()
+
 	return nil
 }
 
@@ -2108,6 +2159,58 @@
 	}
 }
 
+// createOnuUpgradeFsm initializes and runs the Onu Software upgrade FSM
+func (dh *deviceHandler) createOnuUpgradeFsm(ctx context.Context, devEvent OnuDeviceEvent) error {
+	//in here lockUpgradeFsm is already locked
+	chUpgradeFsm := make(chan Message, 2048)
+	var sFsmName = "OnuSwUpgradeFSM"
+	logger.Debugw(ctx, "create OnuSwUpgradeFSM", log.Fields{"device-id": dh.deviceID})
+	pDevEntry := dh.getOnuDeviceEntry(ctx, true)
+	if pDevEntry == nil {
+		logger.Errorw(ctx, "no valid OnuDevice -abort", log.Fields{"device-id": dh.deviceID})
+		return fmt.Errorf(fmt.Sprintf("no valid OnuDevice - abort for device-id: %s", dh.device.Id))
+	}
+	dh.pOnuUpradeFsm = NewOnuUpgradeFsm(ctx, dh, pDevEntry.PDevOmciCC, pDevEntry.pOnuDB, devEvent,
+		sFsmName, chUpgradeFsm)
+	if dh.pOnuUpradeFsm != nil {
+		pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
+		if pUpgradeStatemachine != nil {
+			if pUpgradeStatemachine.Is(upgradeStDisabled) {
+				if err := pUpgradeStatemachine.Event(upgradeEvStart); err != nil {
+					logger.Errorw(ctx, "OnuSwUpgradeFSM: can't start", log.Fields{"err": err})
+					// maybe try a FSM reset and then again ... - TODO!!!
+					return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM could not be started for device-id: %s", dh.device.Id))
+				}
+				/***** LockStateFSM started */
+				logger.Debugw(ctx, "OnuSwUpgradeFSM started", log.Fields{
+					"state": pUpgradeStatemachine.Current(), "device-id": dh.deviceID})
+			} else {
+				logger.Errorw(ctx, "wrong state of OnuSwUpgradeFSM to start - want: disabled", log.Fields{
+					"have": pUpgradeStatemachine.Current(), "device-id": dh.deviceID})
+				// maybe try a FSM reset and then again ... - TODO!!!
+				return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM could not be started for device-id: %s, wrong internal state", dh.device.Id))
+			}
+		} else {
+			logger.Errorw(ctx, "OnuSwUpgradeFSM internal FSM invalid - cannot be executed!!", log.Fields{"device-id": dh.deviceID})
+			// maybe try a FSM reset and then again ... - TODO!!!
+			return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM internal FSM could not be created for device-id: %s", dh.device.Id))
+		}
+	} else {
+		logger.Errorw(ctx, "OnuSwUpgradeFSM could not be created  - abort", log.Fields{"device-id": dh.deviceID})
+		return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM could not be created - abort for device-id: %s", dh.device.Id))
+	}
+	return nil
+}
+
+// removeOnuUpgradeFsm clears the Onu Software upgrade FSM
+func (dh *deviceHandler) removeOnuUpgradeFsm(ctx context.Context) {
+	logger.Debugw(ctx, "remove OnuSwUpgradeFSM StateMachine", log.Fields{
+		"device-id": dh.deviceID})
+	dh.lockUpgradeFsm.Lock()
+	defer dh.lockUpgradeFsm.Unlock()
+	dh.pOnuUpradeFsm = nil //resource clearing is left to garbage collector
+}
+
 //setBackend provides a DB backend for the specified path on the existing KV client
 func (dh *deviceHandler) setBackend(ctx context.Context, aBasePathKvStore string) *db.Backend {
 
@@ -2833,6 +2936,12 @@
 				return true //FSM not active - so there is no activity on omci
 			}
 		}
+	case cOnuUpgradeFsm:
+		{
+			dh.lockUpgradeFsm.RLock()
+			defer dh.lockUpgradeFsm.RUnlock()
+			pFsm = dh.pOnuUpradeFsm.pAdaptFsm.pFsm
+		}
 	default:
 		{
 			logger.Errorw(ctx, "invalid stateMachine selected for idle check", log.Fields{
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 1ad4e8b..a21761b 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -25,9 +25,7 @@
 	"fmt"
 	"strconv"
 	"sync"
-	"time"
-
-	//"time"
+	"time" //by now for testing
 
 	"github.com/google/gopacket"
 	// TODO!!! Some references could be resolved auto, but some need specific context ....
@@ -81,6 +79,7 @@
 type callbackPairEntry struct {
 	cbRespChannel chan Message
 	cbFunction    func(context.Context, *omci.OMCI, *gp.Packet, chan Message) error
+	framePrint    bool //true for printing
 }
 
 //callbackPair to be used for ReceiveCallback init
@@ -90,10 +89,11 @@
 }
 
 type omciTransferStructure struct {
-	txFrame  []byte
-	timeout  int
-	retry    int
-	highPrio bool
+	txFrame        []byte
+	timeout        int
+	retry          int
+	highPrio       bool
+	withFramePrint bool
 }
 
 //omciCC structure holds information needed for OMCI communication (to/from OLT Adapter)
@@ -258,6 +258,14 @@
 	*/
 }
 
+func (oo *omciCC) printRxMessage(ctx context.Context, rxMsg []byte) {
+	//assuming omci message content is hex coded!
+	// with restricted output of 16bytes would be ...rxMsg[:16]
+	logger.Debugw(ctx, "omci-message-received:", log.Fields{
+		"RxOmciMessage": hex.EncodeToString(rxMsg),
+		"device-id":     oo.deviceID})
+}
+
 // Rx handler for onu messages
 //    e.g. would call ReceiveOnuMessage() in case of TID=0 or Action=test ...
 func (oo *omciCC) receiveMessage(ctx context.Context, rxMsg []byte) error {
@@ -293,28 +301,33 @@
 	} else {
 		logger.Errorw(ctx, "received omci-message too small for OmciBaseFormat - abort",
 			log.Fields{"Length": len(rxMsg), "device-id": oo.deviceID})
+		oo.printRxMessage(ctx, rxMsg)
 		return fmt.Errorf("rxOmciMessage too small for BaseFormat %s", oo.deviceID)
 	}
 
 	packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
 	if packet == nil {
 		logger.Errorw(ctx, "omci-message could not be decoded", log.Fields{"device-id": oo.deviceID})
+		oo.printRxMessage(ctx, rxMsg)
 		return fmt.Errorf("could not decode rxMsg as OMCI %s", oo.deviceID)
 	}
 	omciLayer := packet.Layer(omci.LayerTypeOMCI)
 	if omciLayer == nil {
 		logger.Errorw(ctx, "omci-message could not decode omci layer", log.Fields{"device-id": oo.deviceID})
+		oo.printRxMessage(ctx, rxMsg)
 		return fmt.Errorf("could not decode omci layer %s", oo.deviceID)
 	}
 	omciMsg, ok := omciLayer.(*omci.OMCI)
 	if !ok {
 		logger.Errorw(ctx, "omci-message could not assign omci layer", log.Fields{"device-id": oo.deviceID})
+		oo.printRxMessage(ctx, rxMsg)
 		return fmt.Errorf("could not assign omci layer %s", oo.deviceID)
 	}
 	logger.Debugw(ctx, "omci-message-decoded:", log.Fields{"omciMsgType": omciMsg.MessageType,
 		"transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16), "DeviceIdent": omciMsg.DeviceIdentifier})
 	if byte(omciMsg.MessageType)&me.AK == 0 {
 		// Not a response
+		oo.printRxMessage(ctx, rxMsg)
 		logger.Debug(ctx, "RxMsg is no Omci Response Message")
 		if omciMsg.TransactionID == 0 {
 			return oo.receiveOnuMessage(ctx, omciMsg, &packet)
@@ -329,6 +342,9 @@
 	oo.mutexRxSchedMap.Lock()
 	rxCallbackEntry, ok := oo.rxSchedulerMap[omciMsg.TransactionID]
 	if ok && rxCallbackEntry.cbFunction != nil {
+		if rxCallbackEntry.framePrint {
+			oo.printRxMessage(ctx, rxMsg)
+		}
 		//disadvantage of decoupling: error verification made difficult, but anyway the question is
 		// how to react on erroneous frame reception, maybe can simply be ignored
 		go rxCallbackEntry.cbFunction(ctx, omciMsg, &packet, rxCallbackEntry.cbRespChannel)
@@ -339,13 +355,13 @@
 		// having posted the response the request is regarded as 'done'
 		delete(oo.rxSchedulerMap, omciMsg.TransactionID)
 		oo.mutexRxSchedMap.Unlock()
-	} else {
-		oo.mutexRxSchedMap.Unlock()
-		logger.Errorw(ctx, "omci-message-response for not registered transCorrId", log.Fields{"device-id": oo.deviceID, "omciMsg": omciMsg, "transCorrId": omciMsg.TransactionID})
-		return fmt.Errorf("could not find registered response handler tor transCorrId %s", oo.deviceID)
+		return nil
 	}
+	oo.mutexRxSchedMap.Unlock()
+	logger.Errorw(ctx, "omci-message-response for not registered transCorrId", log.Fields{"device-id": oo.deviceID})
+	oo.printRxMessage(ctx, rxMsg)
+	return fmt.Errorf("could not find registered response handler tor transCorrId %s", oo.deviceID)
 
-	return nil
 	/* py code was:
 	           Receive and OMCI message from the proxy channel to the OLT.
 
@@ -464,6 +480,7 @@
 	// it could be checked, if the callback keay is already registered - but simply overwrite may be acceptable ...
 	oo.mutexRxSchedMap.Lock()
 	oo.rxSchedulerMap[receiveCallbackPair.cbKey] = receiveCallbackPair.cbEntry
+	printFrame := receiveCallbackPair.cbEntry.framePrint //printFrame true means debug print of frame is requested
 	oo.mutexRxSchedMap.Unlock()
 
 	//just use a simple list for starting - might need some more effort, especially for multi source write access
@@ -472,6 +489,7 @@
 		timeout,
 		retry,
 		highPrio,
+		printFrame,
 	}
 	oo.mutexTxQueue.Lock()
 	oo.txQueue.PushBack(omciTxRequest) // enqueue
@@ -556,12 +574,13 @@
 			return fmt.Errorf("failed to fetch device %s", oo.deviceID)
 		}
 
-		logger.Debugw(ctx, "omci-message-to-send:", log.Fields{
-			"TxOmciMessage": hex.EncodeToString(omciTxRequest.txFrame),
-			"device-id":     oo.deviceID,
-			"toDeviceType":  oo.pBaseDeviceHandler.ProxyAddressType,
-			"proxyDeviceID": oo.pBaseDeviceHandler.ProxyAddressID})
-
+		if omciTxRequest.withFramePrint {
+			logger.Debugw(ctx, "omci-message-to-send:", log.Fields{
+				"TxOmciMessage": hex.EncodeToString(omciTxRequest.txFrame),
+				"device-id":     oo.deviceID,
+				"toDeviceType":  oo.pBaseDeviceHandler.ProxyAddressType,
+				"proxyDeviceID": oo.pBaseDeviceHandler.ProxyAddressID})
+		}
 		omciMsg := &ic.InterAdapterOmciMessage{Message: omciTxRequest.txFrame}
 		if sendErr := oo.adapterProxy.SendInterAdapterMessage(log.WithSpanFromContext(context.Background(), ctx), omciMsg,
 			ic.InterAdapterMessageType_OMCI_REQUEST,
@@ -673,7 +692,7 @@
 	}
 	omciRxCallbackPair := callbackPair{
 		cbKey:   tid,
-		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse},
+		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse, true},
 	}
 	return oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 }
@@ -694,7 +713,7 @@
 	}
 	omciRxCallbackPair := callbackPair{
 		cbKey:   tid,
-		cbEntry: callbackPairEntry{oo.pOnuDeviceEntry.omciRebootMessageReceivedChannel, oo.receiveOmciResponse},
+		cbEntry: callbackPairEntry{oo.pOnuDeviceEntry.omciRebootMessageReceivedChannel, oo.receiveOmciResponse, true},
 	}
 
 	err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
@@ -731,7 +750,7 @@
 
 	omciRxCallbackPair := callbackPair{
 		cbKey:   tid,
-		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse},
+		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse, true},
 	}
 	return oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 }
@@ -754,8 +773,11 @@
 	oo.uploadSequNo++
 
 	omciRxCallbackPair := callbackPair{
-		cbKey:   tid,
-		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse},
+		cbKey: tid,
+		//frame printing for MibUpload frames disabled now per default to avoid log file abort situations (size/speed?)
+		// if wanted, rx frame printing should be specifically done within the MibUpload FSM or controlled via extra parameter
+		// compare also software upgrade download section handling
+		cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse, false},
 	}
 	return oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 }
@@ -788,7 +810,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -836,7 +858,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -890,7 +912,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -942,7 +964,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -999,7 +1021,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{(*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1044,7 +1066,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1089,7 +1111,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1136,7 +1158,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1182,7 +1204,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1224,7 +1246,7 @@
 		}
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1279,7 +1301,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1322,7 +1344,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1365,7 +1387,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1408,7 +1430,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1449,7 +1471,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1490,7 +1512,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1531,7 +1553,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1577,7 +1599,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1623,7 +1645,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1664,7 +1686,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1705,7 +1727,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1746,7 +1768,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1792,7 +1814,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1838,7 +1860,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1884,7 +1906,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1930,7 +1952,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1976,7 +1998,7 @@
 
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -1992,7 +2014,6 @@
 	return nil
 }
 
-// nolint: unused
 func (oo *omciCC) sendCreateMulticastGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -2016,7 +2037,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2031,7 +2052,6 @@
 	return nil
 }
 
-// nolint: unused
 func (oo *omciCC) sendSetMulticastGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -2055,7 +2075,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2070,7 +2090,6 @@
 	return nil
 }
 
-// nolint: unused
 func (oo *omciCC) sendCreateMulticastOperationProfileVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -2096,7 +2115,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2112,7 +2131,6 @@
 	return nil
 }
 
-// nolint: unused
 func (oo *omciCC) sendSetMulticastOperationProfileVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -2138,7 +2156,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2154,7 +2172,6 @@
 	return nil
 }
 
-// nolint: unused
 func (oo *omciCC) sendCreateMulticastSubConfigInfoVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -2180,7 +2197,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2229,7 +2246,7 @@
 	}
 
 	omciRxCallbackPair := callbackPair{cbKey: tid,
-		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 	}
 	err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 	if err != nil {
@@ -2279,7 +2296,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2331,7 +2348,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2383,7 +2400,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2435,7 +2452,7 @@
 		}
 
 		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
 		}
 		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
 		if err != nil {
@@ -2452,6 +2469,364 @@
 	return nil
 }
 
+func (oo *omciCC) sendStartSoftwareDownload(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aImageMeID uint16, aDownloadWindowSize uint8, aFileLen uint32) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send StartSwDlRequest:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+
+	omciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.StartSoftwareDownloadRequestType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	request := &omci.StartSoftwareDownloadRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		WindowSize:           aDownloadWindowSize,
+		ImageSize:            aFileLen,
+		NumberOfCircuitPacks: 1,           //parallel download to multiple circuit packs not supported
+		CircuitPacks:         []uint16{0}, //circuit pack indication don't care for NumberOfCircuitPacks=1, but needed by omci-lib
+	}
+
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize StartSwDlRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send StartSwDlRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send StartSwDlRequest done")
+
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+	time.Sleep(time.Millisecond * 200) //give some response time
+	respOmciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.StartSoftwareDownloadResponseType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	response := &omci.StartSoftwareDownloadResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		Result:            0,
+		WindowSize:        aDownloadWindowSize,
+		NumberOfInstances: 0, //seems at the moment I can only generate 0 instances, using 1 here panics as MeResult can not be set below
+		//MeResults: cannot set here: downloadResults type not exported from omci-lib!
+	}
+	var respOptions gopacket.SerializeOptions
+	respOptions.FixLengths = true
+	respBuffer := gopacket.NewSerializeBuffer()
+	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+	if respErr != nil {
+		logger.Errorw(ctx, "Cannot serialize StartSwDlResponse", log.Fields{"Err": respErr,
+			"device-id": oo.deviceID})
+		return respErr
+	}
+	respPacket := respBuffer.Bytes()
+	logger.Debugw(ctx, "simulate StartSwDlResponse", log.Fields{"device-id": oo.deviceID,
+		"SequNo":     strconv.FormatInt(int64(tid), 16),
+		"InstId":     strconv.FormatInt(int64(aImageMeID), 16),
+		"windowSize": aDownloadWindowSize})
+	go func(oo *omciCC) {
+		_ = oo.receiveMessage(ctx, respPacket)
+	}(oo)
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	return nil
+}
+
+func (oo *omciCC) sendDownloadSection(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aImageMeID uint16, aAckRequest uint8, aDownloadSectionNo uint8, aSection []byte, aPrint bool) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send DlSectionRequest:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+
+	//TODO!!!: don't know by now on how to generate the possibly needed AR (or enforce it to 0) with current omci-lib
+	//    by now just try to send it as defined by omci-lib
+	omciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.DownloadSectionRequestType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	//TODO!!!: omci-lib wrongly defines just 29 byte data section (which should be 31 bytes)
+	//  as long as this is valid and testing is done with some dummy image we omit the last two bytes in each section!!!
+	var localSectionData [29]byte
+	copy(localSectionData[:], aSection)
+	request := &omci.DownloadSectionRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		SectionNumber: aDownloadSectionNo,
+		SectionData:   localSectionData,
+	}
+
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize DlSectionRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, aPrint},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send DlSectionRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send DlSectionRequest done")
+
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+	if aAckRequest > 0 {
+		time.Sleep(time.Millisecond * 200) //give some response time
+		respOmciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.DownloadSectionResponseType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		response := &omci.DownloadSectionResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			Result:        0,
+			SectionNumber: aDownloadSectionNo,
+		}
+		var respOptions gopacket.SerializeOptions
+		respOptions.FixLengths = true
+		respBuffer := gopacket.NewSerializeBuffer()
+		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+		if respErr != nil {
+			logger.Errorw(ctx, "Cannot serialize DlSectionResponse", log.Fields{"Err": respErr,
+				"device-id": oo.deviceID})
+			return err
+		}
+		respPacket := respBuffer.Bytes()
+		if aPrint {
+			logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
+				"SequNo": strconv.FormatInt(int64(tid), 16),
+				"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+				"packet": hex.EncodeToString(respPacket)})
+		} else {
+			logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
+				"SequNo": strconv.FormatInt(int64(tid), 16),
+				"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+		}
+		go func(oo *omciCC) {
+			_ = oo.receiveMessage(ctx, respPacket)
+		}(oo)
+	}
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	return nil
+}
+
+func (oo *omciCC) sendEndSoftwareDownload(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aImageMeID uint16, aFileLen uint32, aImageCrc uint32) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send EndSwDlRequest:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+
+	//**** test simulation - as long as omci-lib serialize for this type is not corrected - just bypass sending *** start *****
+	/*
+		omciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.EndSoftwareDownloadRequestType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		request := &omci.EndSoftwareDownloadRequest{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			CRC32:             aImageCrc,
+			ImageSize:         aFileLen,
+			NumberOfInstances: 1,           //parallel download to multiple circuit packs not supported
+			ImageInstances:    []uint16{0}, //don't care for NumberOfInstances=1, but probably needed by omci-lib as in startSwDlRequest
+		}
+
+		var options gopacket.SerializeOptions
+		options.FixLengths = true
+		buffer := gopacket.NewSerializeBuffer()
+		err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+		if err != nil {
+			logger.Errorw(ctx, "Cannot serialize EndSwDlRequest", log.Fields{"Err": err,
+				"device-id": oo.deviceID})
+			return err
+		}
+		outgoingPacket := buffer.Bytes()
+
+		omciRxCallbackPair := callbackPair{cbKey: tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+		}
+		err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw(ctx, "Cannot send EndSwDlRequest", log.Fields{"Err": err,
+				"device-id": oo.deviceID})
+			return err
+		}
+	*/
+	//**** test simulation - as long as omci-lib serialize for this type is not corrected - just bypass sending *** end *****
+	logger.Debug(ctx, "send EndSwDlRequest done")
+
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+	//callback code necessary here only as long as sending the request is not possible
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	oo.mutexRxSchedMap.Lock()
+	oo.rxSchedulerMap[omciRxCallbackPair.cbKey] = omciRxCallbackPair.cbEntry
+	oo.mutexRxSchedMap.Unlock()
+	//callback code necessary here only as long as sending the request is not possible
+
+	time.Sleep(time.Millisecond * 200) //give some response time
+	respOmciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.EndSoftwareDownloadResponseType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	response := &omci.EndSoftwareDownloadResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		Result:            0, //simulate done, option would be busy
+		NumberOfInstances: 0, //seems at the moment I can only generate 0 instances, using 1 here panics as MeResult can not be set below
+		//MeResults: cannot set here: downloadResults type not exported from omci-lib!
+	}
+	var respOptions gopacket.SerializeOptions
+	respOptions.FixLengths = true
+	respBuffer := gopacket.NewSerializeBuffer()
+	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+	if respErr != nil {
+		logger.Errorw(ctx, "Cannot serialize EndSwDlResponse", log.Fields{"Err": respErr,
+			"device-id": oo.deviceID})
+		return respErr
+	}
+	respPacket := respBuffer.Bytes()
+	logger.Debugw(ctx, "simulate EndSwDlResponse", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+		"result": 0})
+	go func(oo *omciCC) {
+		_ = oo.receiveMessage(ctx, respPacket)
+	}(oo)
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	return nil
+}
+
+func (oo *omciCC) sendActivateSoftware(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aImageMeID uint16) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send ActivateSwRequest:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+
+	omciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.ActivateSoftwareRequestType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	request := &omci.ActivateSoftwareRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		ActivateFlags: 0, //unconditionally reset as the only relevant option here (regardless of VOIP)
+	}
+
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize ActivateSwRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send ActivateSwRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send ActivateSwRequest done")
+
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+
+	time.Sleep(time.Millisecond * 50) //give some response time
+
+	respOmciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.ActivateSoftwareResponseType,
+		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+		// Length:           0x28,						// Optional, defaults to 40 octets
+	}
+	response := &omci.ActivateSoftwareResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: aImageMeID, //inactive image
+		},
+		Result: 0, //simulate done, option would be busy
+	}
+	var respOptions gopacket.SerializeOptions
+	respOptions.FixLengths = true
+	respBuffer := gopacket.NewSerializeBuffer()
+	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+	if respErr != nil {
+		logger.Errorw(ctx, "Cannot serialize ActivateSwResponse", log.Fields{"Err": respErr,
+			"device-id": oo.deviceID})
+		return respErr
+	}
+	respPacket := respBuffer.Bytes()
+	logger.Debugw(ctx, "simulate ActivateSwResponse", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+		"result": 0})
+	go func(oo *omciCC) {
+		_ = oo.receiveMessage(ctx, respPacket)
+	}(oo)
+	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	return nil
+}
+
 func isResponseWithMibDataSync(msgType omci.MessageType) bool {
 	for _, v := range responsesWithMibDataSync {
 		if v == msgType {
diff --git a/internal/pkg/onuadaptercore/omci_onu_upgrade.go b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
new file mode 100644
index 0000000..7842717
--- /dev/null
+++ b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
@@ -0,0 +1,668 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//Package adaptercoreonu provides the utility for onu devices, flows and statistics
+package adaptercoreonu
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/boguslaw-wojcik/crc32a"
+	"github.com/looplab/fsm"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+	"github.com/opencord/voltha-protos/v4/go/voltha"
+)
+
+const cMaxUint32 = ^uint32(0)
+
+const (
+	// internal predefined values - some off them should later be configurable (perhaps with theses as defaults)
+	cOmciDownloadSectionSize     = 31 //in bytes
+	cOmciDownloadWindowSizeLimit = 31 //in sections for window offset (windowSize(32)-1)
+	//cOmciDownloadWindowRetryMax  = 2    // max attempts for a specific window
+	cOmciSectionInterleaveMilliseconds = 100 //DownloadSection interleave time in milliseconds
+	cOmciEndSwDlDelaySeconds           = 1   //End Software Download delay after last section (may be also configurable?)
+	//cOmciDownloadCompleteTimeout = 5400 //in s for the complete timeout (may be better scale to image size/ noOfWindows)
+)
+
+const (
+	// events of config PON ANI port FSM
+	upgradeEvStart              = "upgradeEvStart"
+	upgradeEvPrepareSwDownload  = "upgradeEvPrepareSwDownload"
+	upgradeEvRxStartSwDownload  = "upgradeEvRxStartSwDownload"
+	upgradeEvWaitWindowAck      = "upgradeEvWaitWindowAck"
+	upgradeEvContinueNextWindow = "upgradeEvContinueNextWindow"
+	upgradeEvEndSwDownload      = "upgradeEvEndSwDownload"
+	upgradeEvRequestActivate    = "upgradeEvRequestActivate"
+	upgradeEvWaitForCommit      = "upgradeEvWaitForCommit"
+	upgradeEvCommitSw           = "upgradeEvCommitSw"
+
+	//upgradeEvTimeoutSimple  = "upgradeEvTimeoutSimple"
+	//upgradeEvTimeoutMids    = "upgradeEvTimeoutMids"
+	upgradeEvReset   = "upgradeEvReset"
+	upgradeEvAbort   = "upgradeEvAbort"
+	upgradeEvRestart = "upgradeEvRestart"
+)
+
+const (
+	// states of config PON ANI port FSM
+	upgradeStDisabled           = "upgradeStDisabled"
+	upgradeStStarting           = "upgradeStStarting"
+	upgradeStPreparingDL        = "upgradeStPreparingDL"
+	upgradeStDLSection          = "upgradeStDLSection"
+	upgradeStVerifyWindow       = "upgradeStVerifyWindow"
+	upgradeStFinalizeDL         = "upgradeStFinalizeDL"
+	upgradeStRequestingActivate = "upgradeStRequestingActivate"
+	upgradeStWaitForCommit      = "upgradeStWaitForCommit"
+	upgradeStCommitSw           = "upgradeStCommitSw"
+	upgradeStResetting          = "upgradeStResetting"
+)
+
+//required definition for IdleState detection for activities on OMCI
+const cOnuUpgradeFsmIdleState = upgradeStWaitForCommit
+
+//OnuUpgradeFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
+type OnuUpgradeFsm struct {
+	pDeviceHandler   *deviceHandler
+	pDownloadManager *adapterDownloadManager
+	deviceID         string
+	pOmciCC          *omciCC
+	pOnuDB           *onuDeviceDB
+	requestEvent     OnuDeviceEvent
+	//omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
+	pAdaptFsm                         *AdapterFsm
+	pImageDsc                         *voltha.ImageDownload
+	imageBuffer                       []byte
+	origImageLength                   uint32        //as also limited by OMCI
+	imageLength                       uint32        //including last bytes padding
+	omciDownloadWindowSizeLimit       uint8         //windowSize-1
+	noOfSections                      uint32        //uint32 range for sections should be sufficient for very long images
+	nextDownloadSectionsAbsolute      uint32        //number of next section to download in overall image
+	nextDownloadSectionsWindow        uint8         //number of next section to download within current window
+	noOfWindows                       uint32        //uint32 range for windows should be sufficient for very long images
+	nextDownloadWindow                uint32        //number of next window to download
+	inactiveImageMeID                 uint16        //ME-ID of the inactive image
+	omciSectionInterleaveMilliseconds time.Duration //DownloadSectionInterleave delay in milliseconds
+	delayEndSwDl                      bool          //flag to provide a delay between last section and EndSwDl
+}
+
+//NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
+//  of ONU UNI ports via OMCI
+func NewOnuUpgradeFsm(ctx context.Context, apDeviceHandler *deviceHandler,
+	apDevOmciCC *omciCC, apOnuDB *onuDeviceDB,
+	aRequestEvent OnuDeviceEvent, aName string, aCommChannel chan Message) *OnuUpgradeFsm {
+	instFsm := &OnuUpgradeFsm{
+		pDeviceHandler:                    apDeviceHandler,
+		deviceID:                          apDeviceHandler.deviceID,
+		pOmciCC:                           apDevOmciCC,
+		pOnuDB:                            apOnuDB,
+		requestEvent:                      aRequestEvent,
+		omciDownloadWindowSizeLimit:       cOmciDownloadWindowSizeLimit,
+		omciSectionInterleaveMilliseconds: cOmciSectionInterleaveMilliseconds,
+	}
+
+	instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
+	if instFsm.pAdaptFsm == nil {
+		logger.Errorw(ctx, "OnuUpgradeFsm's AdapterFsm could not be instantiated!!", log.Fields{
+			"device-id": instFsm.deviceID})
+		return nil
+	}
+	instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
+		upgradeStDisabled,
+		fsm.Events{
+			{Name: upgradeEvStart, Src: []string{upgradeStDisabled}, Dst: upgradeStStarting},
+			{Name: upgradeEvPrepareSwDownload, Src: []string{upgradeStStarting}, Dst: upgradeStPreparingDL},
+			{Name: upgradeEvRxStartSwDownload, Src: []string{upgradeStPreparingDL}, Dst: upgradeStDLSection},
+			{Name: upgradeEvWaitWindowAck, Src: []string{upgradeStDLSection}, Dst: upgradeStVerifyWindow},
+			{Name: upgradeEvContinueNextWindow, Src: []string{upgradeStVerifyWindow}, Dst: upgradeStDLSection},
+			{Name: upgradeEvEndSwDownload, Src: []string{upgradeStVerifyWindow}, Dst: upgradeStFinalizeDL},
+			{Name: upgradeEvRequestActivate, Src: []string{upgradeStFinalizeDL}, Dst: upgradeStRequestingActivate},
+			{Name: upgradeEvWaitForCommit, Src: []string{upgradeStRequestingActivate}, Dst: upgradeStWaitForCommit},
+			{Name: upgradeEvCommitSw, Src: []string{upgradeStStarting, upgradeStWaitForCommit},
+				Dst: upgradeStCommitSw},
+
+			/*
+				{Name: upgradeEvTimeoutSimple, Src: []string{
+					upgradeStCreatingDot1PMapper, upgradeStCreatingMBPCD, upgradeStSettingTconts, upgradeStSettingDot1PMapper}, Dst: upgradeStStarting},
+				{Name: upgradeEvTimeoutMids, Src: []string{
+					upgradeStCreatingGemNCTPs, upgradeStCreatingGemIWs, upgradeStSettingPQs}, Dst: upgradeStStarting},
+			*/
+			// exceptional treatments
+			{Name: upgradeEvReset, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
+				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
+				upgradeStCommitSw}, //upgradeStWaitForCommit is not reset (later perhaps also not upgradeStWaitActivate)
+				Dst: upgradeStResetting},
+			{Name: upgradeEvAbort, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
+				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
+				upgradeStWaitForCommit, upgradeStCommitSw},
+				Dst: upgradeStResetting},
+			{Name: upgradeEvRestart, Src: []string{upgradeStResetting}, Dst: upgradeStDisabled},
+		},
+		fsm.Callbacks{
+			"enter_state":                          func(e *fsm.Event) { instFsm.pAdaptFsm.logFsmStateChange(ctx, e) },
+			"enter_" + upgradeStStarting:           func(e *fsm.Event) { instFsm.enterStarting(ctx, e) },
+			"enter_" + upgradeStPreparingDL:        func(e *fsm.Event) { instFsm.enterPreparingDL(ctx, e) },
+			"enter_" + upgradeStDLSection:          func(e *fsm.Event) { instFsm.enterDownloadSection(ctx, e) },
+			"enter_" + upgradeStVerifyWindow:       func(e *fsm.Event) { instFsm.enterVerifyWindow(ctx, e) },
+			"enter_" + upgradeStFinalizeDL:         func(e *fsm.Event) { instFsm.enterFinalizeDL(ctx, e) },
+			"enter_" + upgradeStRequestingActivate: func(e *fsm.Event) { instFsm.enterActivateSw(ctx, e) },
+			"enter_" + upgradeStCommitSw:           func(e *fsm.Event) { instFsm.enterCommitSw(ctx, e) },
+			"enter_" + upgradeStResetting:          func(e *fsm.Event) { instFsm.enterResetting(ctx, e) },
+			"enter_" + upgradeStDisabled:           func(e *fsm.Event) { instFsm.enterDisabled(ctx, e) },
+		},
+	)
+	if instFsm.pAdaptFsm.pFsm == nil {
+		logger.Errorw(ctx, "OnuUpgradeFsm's Base FSM could not be instantiated!!", log.Fields{
+			"device-id": instFsm.deviceID})
+		return nil
+	}
+
+	logger.Debugw(ctx, "OnuUpgradeFsm created", log.Fields{"device-id": instFsm.deviceID})
+	return instFsm
+}
+
+//SetDownloadParams configures the needed parameters for a specific download to the ONU
+func (oFsm *OnuUpgradeFsm) SetDownloadParams(ctx context.Context, apImageDsc *voltha.ImageDownload,
+	apDownloadManager *adapterDownloadManager) error {
+	pBaseFsm := oFsm.pAdaptFsm.pFsm
+	if pBaseFsm != nil && pBaseFsm.Is(upgradeStStarting) {
+		logger.Debugw(ctx, "OnuUpgradeFsm Parameter setting", log.Fields{
+			"device-id": oFsm.deviceID, "image-description": apImageDsc})
+		oFsm.pImageDsc = apImageDsc
+		oFsm.pDownloadManager = apDownloadManager
+
+		go func(aPBaseFsm *fsm.FSM) {
+			// let the upgrade FSm proceed to PreparinDL
+			_ = aPBaseFsm.Event(upgradeEvPrepareSwDownload)
+		}(pBaseFsm)
+		return nil
+	}
+	logger.Errorw(ctx, "OnuUpgradeFsm abort: invalid FSM base pointer or state", log.Fields{
+		"device-id": oFsm.deviceID})
+	return fmt.Errorf(fmt.Sprintf("OnuUpgradeFsm abort: invalid FSM base pointer or state for device-id: %s", oFsm.deviceID))
+}
+
+func (oFsm *OnuUpgradeFsm) enterStarting(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm start", log.Fields{"in state": e.FSM.Current(),
+		"device-id": oFsm.deviceID})
+
+	// start go routine for processing of LockState messages
+	go oFsm.processOmciUpgradeMessages(ctx)
+}
+
+func (oFsm *OnuUpgradeFsm) enterPreparingDL(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm prepare Download to Onu", log.Fields{"in state": e.FSM.Current(),
+		"device-id": oFsm.deviceID})
+
+	fileLen, err := oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
+	if err != nil || fileLen > int64(cMaxUint32) {
+		logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
+			"device-id": oFsm.deviceID, "error": err, "length": fileLen})
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pBaseFsm)
+		return
+	}
+
+	oFsm.imageBuffer = make([]byte, fileLen)
+	oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
+	if err != nil {
+		logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
+			"device-id": oFsm.deviceID, "error": err})
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pBaseFsm)
+		return
+	}
+
+	oFsm.noOfSections = uint32(fileLen / cOmciDownloadSectionSize)
+	if fileLen%cOmciDownloadSectionSize > 0 {
+		bufferPadding := make([]byte, cOmciDownloadSectionSize-uint32(fileLen%cOmciDownloadSectionSize))
+		//expand the imageBuffer to exactly fit multiples of cOmciDownloadSectionSize with padding
+		oFsm.imageBuffer = append(oFsm.imageBuffer[:fileLen], bufferPadding...)
+		oFsm.noOfSections++
+	}
+	oFsm.origImageLength = uint32(fileLen)
+	oFsm.imageLength = uint32(len(oFsm.imageBuffer))
+	oFsm.inactiveImageMeID = uint16(1) //just to start with, must be detected from upload data or even determined per new request?
+
+	logger.Infow(ctx, "OnuUpgradeFsm starts with StartSwDl values", log.Fields{
+		"MeId": oFsm.inactiveImageMeID, "windowSizeLimit": oFsm.omciDownloadWindowSizeLimit,
+		"ImageSize": oFsm.imageLength, "original file size": fileLen})
+	//"NumberOfCircuitPacks": oFsm.numberCircuitPacks, "CircuitPacks MeId": 0}) //parallel circuit packs download not supported
+	err = oFsm.pOmciCC.sendStartSoftwareDownload(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
+		oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, oFsm.omciDownloadWindowSizeLimit, oFsm.origImageLength)
+	if err != nil {
+		logger.Errorw(ctx, "StartSwDl abort: can't send section", log.Fields{
+			"device-id": oFsm.deviceID, "error": err})
+		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pBaseFsm)
+		return
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) enterDownloadSection(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm start downloading sections", log.Fields{
+		"device-id": oFsm.deviceID, "absolute window": oFsm.nextDownloadWindow})
+
+	var windowAckRequest uint8 = 0
+	var bufferStartOffset uint32
+	var bufferEndOffset uint32
+	var downloadSection []byte
+	framePrint := false //default no printing of downloadSection frames
+	if oFsm.nextDownloadSectionsAbsolute == 0 {
+		//debug print of first section frame
+		framePrint = true
+	}
+
+	for {
+		bufferStartOffset = oFsm.nextDownloadSectionsAbsolute * cOmciDownloadSectionSize
+		bufferEndOffset = bufferStartOffset + cOmciDownloadSectionSize - 1 //for representing cOmciDownloadSectionSizeLimit values
+		logger.Debugw(ctx, "DlSection values are", log.Fields{
+			"DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute,
+			"DlSectionWindow":     oFsm.nextDownloadSectionsWindow,
+			"startOffset":         bufferStartOffset, "endOffset": bufferEndOffset})
+		if bufferStartOffset+1 > oFsm.imageLength || bufferEndOffset+1 > oFsm.imageLength { //should never occur in this state
+			logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
+				"device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
+				"bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
+			//logical error -- reset the FSM
+			pBaseFsm := oFsm.pAdaptFsm
+			// Can't call FSM Event directly, decoupling it
+			go func(a_pAFsm *AdapterFsm) {
+				_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			}(pBaseFsm)
+			return
+		}
+		downloadSection = oFsm.imageBuffer[bufferStartOffset : bufferEndOffset+1]
+		if oFsm.nextDownloadSectionsWindow == oFsm.omciDownloadWindowSizeLimit {
+			windowAckRequest = 1
+			logger.Debugw(ctx, "DlSection expect Response for complete window", log.Fields{
+				"device-id": oFsm.deviceID, "in window": oFsm.nextDownloadWindow})
+		}
+		if oFsm.nextDownloadSectionsAbsolute+1 >= oFsm.noOfSections {
+			windowAckRequest = 1
+			framePrint = true //debug print of last frame
+			logger.Debugw(ctx, "DlSection expect Response for last window (section)", log.Fields{
+				"device-id": oFsm.deviceID, "DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute})
+		}
+		err := oFsm.pOmciCC.sendDownloadSection(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
+			oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, windowAckRequest, oFsm.nextDownloadSectionsWindow, downloadSection, framePrint)
+		if err != nil {
+			logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
+				"device-id": oFsm.deviceID, "error": err})
+			//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+			pBaseFsm := oFsm.pAdaptFsm
+			// Can't call FSM Event directly, decoupling it
+			go func(a_pAFsm *AdapterFsm) {
+				_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			}(pBaseFsm)
+			return
+		}
+
+		oFsm.nextDownloadSectionsAbsolute++ //always increase the absolute section counter after having sent one
+		if windowAckRequest == 1 {
+			pBaseFsm := oFsm.pAdaptFsm
+			// Can't call FSM Event directly, decoupling it
+			go func(a_pAFsm *AdapterFsm) {
+				_ = a_pAFsm.pFsm.Event(upgradeEvWaitWindowAck) //state transition to upgradeStVerifyWindow
+			}(pBaseFsm)
+			return
+		}
+		framePrint = false                //for the next Section frame (if wanted, can be enabled in logic before sendXXX())
+		oFsm.nextDownloadSectionsWindow++ //increase the window related section counter only if not in the last section
+		if oFsm.omciSectionInterleaveMilliseconds > 0 {
+			//ensure a defined intersection-time-gap to leave space for further processing, other ONU's ...
+			time.Sleep(oFsm.omciSectionInterleaveMilliseconds * time.Millisecond)
+		}
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) enterVerifyWindow(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm verify DL window ack", log.Fields{
+		"for window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
+}
+
+func (oFsm *OnuUpgradeFsm) enterFinalizeDL(ctx context.Context, e *fsm.Event) {
+	imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //ITU I.363.5 crc
+	logger.Infow(ctx, "OnuUpgradeFsm finalize DL", log.Fields{
+		"device-id": oFsm.deviceID, "crc": strconv.FormatInt(int64(imageCRC), 16), "delay": oFsm.delayEndSwDl})
+
+	if oFsm.delayEndSwDl {
+		//give the ONU some time for image evaluation (hoping it does not base that on first EndSwDl itself)
+		// should not be set in case this state is used for real download abort (not yet implemented)
+		time.Sleep(cOmciEndSwDlDelaySeconds * time.Second)
+	}
+
+	err := oFsm.pOmciCC.sendEndSoftwareDownload(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
+		oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, oFsm.origImageLength, imageCRC)
+	if err != nil {
+		logger.Errorw(ctx, "EndSwDl abort: can't send section", log.Fields{
+			"device-id": oFsm.deviceID, "error": err})
+		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pBaseFsm)
+		return
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) enterActivateSw(ctx context.Context, e *fsm.Event) {
+	logger.Infow(ctx, "OnuUpgradeFsm activate SW", log.Fields{
+		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
+
+	err := oFsm.pOmciCC.sendActivateSoftware(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
+		oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID)
+	if err != nil {
+		logger.Errorw(ctx, "ActivateSw abort: can't send activate frame", log.Fields{
+			"device-id": oFsm.deviceID, "error": err})
+		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+		}(pBaseFsm)
+		return
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) enterCommitSw(ctx context.Context, e *fsm.Event) {
+	logger.Infow(ctx, "OnuUpgradeFsm commit SW - not yet implemented", log.Fields{
+		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
+	//here should be the sending of the software commit message and staying here while waiting for the response
+}
+
+func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm resetting", log.Fields{"device-id": oFsm.deviceID})
+
+	pConfigupgradeStateAFsm := oFsm.pAdaptFsm
+	if pConfigupgradeStateAFsm != nil {
+		// abort running message processing
+		fsmAbortMsg := Message{
+			Type: TestMsg,
+			Data: TestMessage{
+				TestMessageVal: AbortMessageProcessing,
+			},
+		}
+		pConfigupgradeStateAFsm.commChan <- fsmAbortMsg
+
+		//try to restart the FSM to 'disabled'
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			if a_pAFsm != nil && a_pAFsm.pFsm != nil {
+				_ = a_pAFsm.pFsm.Event(upgradeEvRestart)
+			}
+		}(pConfigupgradeStateAFsm)
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) enterDisabled(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm enters disabled state", log.Fields{"device-id": oFsm.deviceID})
+	if oFsm.pDeviceHandler != nil {
+		//request removal of 'reference' in the Handler (completely clear the FSM and its data)
+		go oFsm.pDeviceHandler.removeOnuUpgradeFsm(ctx)
+	}
+}
+
+func (oFsm *OnuUpgradeFsm) processOmciUpgradeMessages(ctx context.Context) { //ctx context.Context?
+	logger.Debugw(ctx, "Start OnuUpgradeFsm Msg processing", log.Fields{"for device-id": oFsm.deviceID})
+loop:
+	for {
+		// case <-ctx.Done():
+		// 	logger.Info(ctx,"MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.deviceID})
+		// 	break loop
+		message, ok := <-oFsm.pAdaptFsm.commChan
+		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.pAdaptFsm.pFsm.Event(upgradeEvReset)
+			break loop
+		}
+		logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
+
+		switch message.Type {
+		case TestMsg:
+			msg, _ := message.Data.(TestMessage)
+			if msg.TestMessageVal == AbortMessageProcessing {
+				logger.Infow(ctx, "OnuUpgradeFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.deviceID})
+				break loop
+			}
+			logger.Warnw(ctx, "OnuUpgradeFsm unknown TestMessage", log.Fields{"device-id": oFsm.deviceID, "MessageVal": msg.TestMessageVal})
+		case OMCI:
+			msg, _ := message.Data.(OmciMessage)
+			oFsm.handleOmciOnuUpgradeMessage(ctx, msg)
+		default:
+			logger.Warn(ctx, "OnuUpgradeFsm Rx unknown message", log.Fields{"device-id": oFsm.deviceID,
+				"message.Type": message.Type})
+		}
+	}
+	logger.Infow(ctx, "End OnuUpgradeFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
+}
+
+//nolint: gocyclo
+func (oFsm *OnuUpgradeFsm) handleOmciOnuUpgradeMessage(ctx context.Context, msg OmciMessage) {
+	logger.Debugw(ctx, "Rx OMCI OnuUpgradeFsm Msg", log.Fields{"device-id": oFsm.deviceID,
+		"msgType": msg.OmciMsg.MessageType})
+
+	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})
+				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})
+				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})
+				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+				return
+			}
+			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.pAdaptFsm.pFsm.Event(upgradeEvRxStartSwDownload)
+				return
+			}
+			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: possibly repeat the start request (once)?
+			return
+		} //StartSoftwareDownloadResponseType
+	case omci.DownloadSectionResponseType:
+		{
+			/* TODO!!!: Have to remove the check here as current used omci-lib does not allow msg layering here
+			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})
+				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})
+				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})
+				return
+			}
+			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				sectionNumber := msgObj.SectionNumber
+			*/
+			sectionNumber := oFsm.omciDownloadWindowSizeLimit //as long as access from omci-lib is not given above!!!
+			logger.Debugw(ctx, "DlSectionResponse received", log.Fields{
+				"window section-number": sectionNumber, "device-id": oFsm.deviceID})
+			if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
+				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
+					log.Fields{"device-id": oFsm.deviceID, "window-section-limit": oFsm.omciDownloadWindowSizeLimit})
+				return
+			}
+
+			oFsm.nextDownloadWindow++
+			if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
+				oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvEndSwDownload)
+				return
+			}
+			oFsm.nextDownloadSectionsWindow = 0
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvContinueNextWindow)
+			return
+			/* }
+			logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: possibly repeat the start request (once)?
+			return
+			*/
+		} //DownloadSectionResponseType
+	case omci.EndSoftwareDownloadResponseType:
+		{
+			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})
+				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})
+				return
+			}
+			logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
+				"device-id": oFsm.deviceID, "data-fields": msgObj})
+			if msgObj.Result != me.Success {
+				//TODO!!: Busy must be handled to give the ONU time for internal image storage, perhaps also processing error (CRC incorrect)
+				logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
+					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+				return
+			}
+			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvRequestActivate)
+				return
+			}
+			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: possibly repeat the end request (once)? or verify ONU upgrade state?
+			return
+		} //EndSoftwareDownloadResponseType
+	case omci.ActivateSoftwareResponseType:
+		{
+			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeActivateSoftwareResponse)
+			if msgLayer == nil {
+				logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
+					log.Fields{"device-id": oFsm.deviceID})
+				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})
+				return
+			}
+			logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
+				"device-id": oFsm.deviceID, "data-fields": msgObj})
+			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})
+				// TODO!!!: error treatment?, perhaps in the end reset the FSM
+				return
+			}
+			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				logger.Debugw(ctx, "Expected ActivateSwResponse received", log.Fields{"device-id": oFsm.deviceID})
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvWaitForCommit)
+				return
+			}
+			logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: error treatment?, perhaps in the end reset the FSM
+			return
+		} //ActivateSoftwareResponseType
+	default:
+		{
+			logger.Errorw(ctx, "Rx OMCI unhandled MsgType",
+				log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "device-id": oFsm.deviceID})
+			return
+		}
+	}
+}
+
+/*
+func (oFsm *OnuUpgradeFsm) waitforOmciResponse(ctx context.Context) error {
+	select {
+	// maybe be also some outside cancel (but no context modeled for the moment ...)
+	// case <-ctx.Done():
+	// 		logger.Infow(ctx,"LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.deviceID})
+	case <-time.After(30 * time.Second): //AS FOR THE OTHER OMCI FSM's
+		logger.Warnw(ctx, "OnuUpgradeFsm multi entity timeout", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("OnuUpgradeFsm multi entity timeout %s", oFsm.deviceID)
+	case success := <-oFsm.omciMIdsResponseReceived:
+		if success {
+			logger.Debug(ctx, "OnuUpgradeFsm multi entity response received")
+			return nil
+		}
+		// should not happen so far
+		logger.Warnw(ctx, "OnuUpgradeFsm multi entity response error", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("OnuUpgradeFsm multi entity responseError %s", oFsm.deviceID)
+	}
+}
+*/
diff --git a/internal/pkg/onuadaptercore/omci_test_request.go b/internal/pkg/onuadaptercore/omci_test_request.go
index fb8dceb..410dda0 100644
--- a/internal/pkg/onuadaptercore/omci_test_request.go
+++ b/internal/pkg/onuadaptercore/omci_test_request.go
@@ -75,7 +75,7 @@
 		onu2gBaseGet, _ := oo.createOnu2gBaseGet(ctx, tid)
 		omciRxCallbackPair := callbackPair{
 			cbKey:   tid,
-			cbEntry: callbackPairEntry{nil, oo.receiveOmciVerifyResponse},
+			cbEntry: callbackPairEntry{nil, oo.receiveOmciVerifyResponse, true},
 		}
 
 		logger.Debugw(ctx, "performOmciTest-start sending frame", log.Fields{"for device-id": oo.deviceID})
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index 816ebcd..301a973 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -154,6 +154,8 @@
 	OmciVlanFilterRemDone // needs to be the successor of OmciVlanFilterAddDoneNoKvStore!
 	// OmciVlanFilterRemDoneNoKvStore - Omci Vlan config done according to flow-remove without writing kvStore
 	OmciVlanFilterRemDoneNoKvStore // needs to be the successor of OmciVlanFilterRemDone!
+	// OmciOnuSwUpgradeDone - SoftwareUpgrade to ONU finished
+	OmciOnuSwUpgradeDone
 	// Add other events here as needed (alarms separate???)
 )
 
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index b77276e..460c7c8 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -479,11 +479,11 @@
 //Activate_image_update requests downloading some Onu Software image to the INU via OMCI
 //  according to indications as given in apRequest and on success activate the image on the ONU
 func (oo *OpenONUAC) Activate_image_update(ctx context.Context, device *voltha.Device, apRequest *voltha.ImageDownload) (*voltha.ImageDownload, error) {
-	if oo.pDownloadManager.imageExists(ctx, apRequest) {
+	if oo.pDownloadManager.imageLocallyDownloaded(ctx, apRequest) {
 		if handler := oo.getDeviceHandler(ctx, device.Id, false); handler != nil {
 			logger.Debugw(ctx, "image download on omci requested", log.Fields{
 				"image-description": apRequest, "device-id": device.Id})
-			err := handler.doOnuSwUpgrade(ctx, apRequest)
+			err := handler.doOnuSwUpgrade(ctx, apRequest, oo.pDownloadManager)
 			return apRequest, err
 		}
 		logger.Warnw(ctx, "no handler found for image activation", log.Fields{"device-id": device.Id})
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore b/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore
new file mode 100644
index 0000000..a09c56d
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore
@@ -0,0 +1 @@
+/.idea
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE b/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE
new file mode 100644
index 0000000..e24c314
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 BogusÅ‚aw Wójcik
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/README.md b/vendor/github.com/boguslaw-wojcik/crc32a/README.md
new file mode 100644
index 0000000..6b2fea8
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/README.md
@@ -0,0 +1,40 @@
+# CRC32A
+A pure Go implementation of CRC32A (ITU I.363.5) checksum missing from Golang standard library. Largely based on C implementation found in PHP source files.
+
+## Usage
+
+```go
+package main
+
+import (
+	"fmt"
+	
+	"github.com/boguslaw-wojcik/crc32a"
+)
+
+func main() {
+	b := []byte("123456789")
+	sum := crc32a.Checksum(b)
+	sumHex := crc32a.ChecksumHex(b)
+
+	fmt.Println(sum)    // 404326908
+	fmt.Println(sumHex) // 181989fc
+}
+```
+
+## Background
+There are four popular implementations of CRC32 of which three are included in Golang standard library. This package provides missing implementation of CRC32A (ITU I.363.5) popularized by bzip2 and PHP. If you're unsure what CRC32 algorithm you're using, calculate checksum for string `123456789` and compare results with the table below.
+
+| Variant | Performance | Standard Library | Data | Hex | Sum |
+| :--- | :---: | :---: | :---: | :---: | ---: |
+| **CRC32A (ITU I.363.5)** | **31.4 ns/op** | **no** | **123456789** | **181989fc** | **404326908** |
+| CRC32B (ITU V.42 / IEEE 802.3) | 24.0 ns/op | yes | 123456789 | cbf43926 | 3421780262 |
+| CRC32C (Castagnoli) | 15.2 ns/op | yes | 123456789 | e3069283 | 3808858755 |
+| CRC32K (Koopman) | 4534 ns/op | yes | 123456789 | 2d3dd0ae | 759025838 |
+
+_Note: Unless you're required to use CRC32A for legacy reasons, in general you should choose CRC32B as the most popular and widely implemented CRC32 variation._
+
+## References
+
+* [CRC32 Demystified](https://github.com/Michaelangel007/crc32) by Michael Pohoreski
+* [PHP CRC32 source](https://github.com/php/php-src/blob/php-7.3.1/ext/hash/hash_crc32.c) by PHP Group
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go b/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go
new file mode 100644
index 0000000..7f13216
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go
@@ -0,0 +1,99 @@
+package crc32a
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+)
+
+// Checksum calculates CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum.
+// This function will produce the same results as following PHP code:
+//  hexdec(hash('crc32', $data))
+func Checksum(data []byte) uint32 {
+	b := digest(data)
+
+	return binary.BigEndian.Uint32(b)
+}
+
+// ChecksumHex is a convenience function that outputs CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum as a hex string.
+// This function will produce the same results as following PHP code:
+//  hash('crc32', $data)
+func ChecksumHex(data []byte) string {
+	b := digest(data)
+
+	return hex.EncodeToString(b)
+}
+
+// digest performs checksum calculation for each byte of provided data and returns digest in form of byte array.
+func digest(data []byte) []byte {
+	var crc uint32
+	var digest = make([]byte, 4)
+
+	crc = ^crc
+	for i := 0; i < len(data); i++ {
+		crc = (crc << 8) ^ table[(crc >> 24) ^ (uint32(data[i]) & 0xff)]
+	}
+	crc = ^crc
+
+	digest[3] = byte((crc >> 24) & 0xff)
+	digest[2] = byte((crc >> 16) & 0xff)
+	digest[1] = byte((crc >> 8) & 0xff)
+	digest[0] = byte(crc & 0xff)
+
+	return digest
+}
+
+// table is the pre-generated 0x04C11DB7 polynominal used for CRC32A.
+var table = [256]uint32{
+	0x0,
+	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
+}
\ No newline at end of file
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/go.mod b/vendor/github.com/boguslaw-wojcik/crc32a/go.mod
new file mode 100644
index 0000000..27b7a70
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/go.mod
@@ -0,0 +1 @@
+module github.com/boguslaw-wojcik/crc32a
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/adapters/common/request_handler.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/adapters/common/request_handler.go
index 7d14db7..459cac5 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/adapters/common/request_handler.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/adapters/common/request_handler.go
@@ -559,24 +559,107 @@
 	return new(empty.Empty), nil
 }
 
-func (rhp *RequestHandlerProxy) Download_image(args []*ic.Argument) (*voltha.ImageDownload, error) {
-	return &voltha.ImageDownload{}, nil
+func (rhp *RequestHandlerProxy) Download_image(ctx context.Context, args []*ic.Argument) (*voltha.ImageDownload, error) {
+	device, image, err := unMarshalImageDowload(args, ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	imageDownload, err := rhp.adapter.Download_image(ctx, device, image)
+	if err != nil {
+		return nil, status.Errorf(codes.NotFound, "%s", err.Error())
+	}
+	return imageDownload, nil
 }
 
-func (rhp *RequestHandlerProxy) Get_image_download_status(args []*ic.Argument) (*voltha.ImageDownload, error) {
-	return &voltha.ImageDownload{}, nil
+func (rhp *RequestHandlerProxy) Get_image_download_status(ctx context.Context, args []*ic.Argument) (*voltha.ImageDownload, error) {
+	device, image, err := unMarshalImageDowload(args, ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	imageDownload, err := rhp.adapter.Get_image_download_status(ctx, device, image)
+	if err != nil {
+		return nil, status.Errorf(codes.NotFound, "%s", err.Error())
+	}
+	return imageDownload, nil
 }
 
-func (rhp *RequestHandlerProxy) Cancel_image_download(args []*ic.Argument) (*voltha.ImageDownload, error) {
-	return &voltha.ImageDownload{}, nil
+func (rhp *RequestHandlerProxy) Cancel_image_download(ctx context.Context, args []*ic.Argument) (*voltha.ImageDownload, error) {
+	device, image, err := unMarshalImageDowload(args, ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	imageDownload, err := rhp.adapter.Cancel_image_download(ctx, device, image)
+	if err != nil {
+		return nil, status.Errorf(codes.NotFound, "%s", err.Error())
+	}
+	return imageDownload, nil
 }
 
-func (rhp *RequestHandlerProxy) Activate_image_update(args []*ic.Argument) (*voltha.ImageDownload, error) {
-	return &voltha.ImageDownload{}, nil
+func (rhp *RequestHandlerProxy) Activate_image_update(ctx context.Context, args []*ic.Argument) (*voltha.ImageDownload, error) {
+
+	device, image, err := unMarshalImageDowload(args, ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	imageDownload, err := rhp.adapter.Activate_image_update(ctx, device, image)
+	if err != nil {
+		return nil, status.Errorf(codes.NotFound, "%s", err.Error())
+	}
+	return imageDownload, nil
 }
 
-func (rhp *RequestHandlerProxy) Revert_image_update(args []*ic.Argument) (*voltha.ImageDownload, error) {
-	return &voltha.ImageDownload{}, nil
+func (rhp *RequestHandlerProxy) Revert_image_update(ctx context.Context, args []*ic.Argument) (*voltha.ImageDownload, error) {
+	device, image, err := unMarshalImageDowload(args, ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	imageDownload, err := rhp.adapter.Revert_image_update(ctx, device, image)
+	if err != nil {
+		return nil, status.Errorf(codes.NotFound, "%s", err.Error())
+	}
+	return imageDownload, nil
+}
+
+func unMarshalImageDowload(args []*ic.Argument, ctx context.Context) (*voltha.Device, *voltha.ImageDownload, error) {
+	if len(args) < 4 {
+		logger.Warn(ctx, "invalid-number-of-args", log.Fields{"args": args})
+		err := errors.New("invalid-number-of-args")
+		return nil, nil, err
+	}
+	device := &voltha.Device{}
+	image := &voltha.ImageDownload{}
+	transactionID := &ic.StrType{}
+	fromTopic := &ic.StrType{}
+	for _, arg := range args {
+		switch arg.Key {
+		case "device":
+			if err := ptypes.UnmarshalAny(arg.Value, device); err != nil {
+				logger.Warnw(ctx, "cannot-unmarshal-device", log.Fields{"error": err})
+				return nil, nil, err
+			}
+		case "request":
+			if err := ptypes.UnmarshalAny(arg.Value, image); err != nil {
+				logger.Warnw(ctx, "cannot-unmarshal-image", log.Fields{"error": err})
+				return nil, nil, err
+			}
+		case kafka.TransactionKey:
+			if err := ptypes.UnmarshalAny(arg.Value, transactionID); err != nil {
+				logger.Warnw(ctx, "cannot-unmarshal-transaction-ID", log.Fields{"error": err})
+				return nil, nil, err
+			}
+		case kafka.FromTopic:
+			if err := ptypes.UnmarshalAny(arg.Value, fromTopic); err != nil {
+				logger.Warnw(ctx, "cannot-unmarshal-from-topic", log.Fields{"error": err})
+				return nil, nil, err
+			}
+		}
+	}
+	return device, image, nil
 }
 
 func (rhp *RequestHandlerProxy) Enable_port(ctx context.Context, args []*ic.Argument) error {
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/events/events_proxy.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/events/events_proxy.go
index a4b12f7..c4014ee 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/events/events_proxy.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/events/events_proxy.go
@@ -78,6 +78,8 @@
 	header.Category = category
 	if subCategory != nil {
 		header.SubCategory = *subCategory
+	} else {
+		header.SubCategory = voltha.EventSubCategory_NONE
 	}
 	header.Type = eventType
 	header.TypeVersion = eventif.EventTypeVersion
diff --git a/vendor/github.com/opencord/voltha-protos/v4/go/voltha/events.pb.go b/vendor/github.com/opencord/voltha-protos/v4/go/voltha/events.pb.go
index f51a7b7..2dc1826 100644
--- a/vendor/github.com/opencord/voltha-protos/v4/go/voltha/events.pb.go
+++ b/vendor/github.com/opencord/voltha-protos/v4/go/voltha/events.pb.go
@@ -116,11 +116,12 @@
 type EventSubCategory_Types int32
 
 const (
-	EventSubCategory_PON EventSubCategory_Types = 0
-	EventSubCategory_OLT EventSubCategory_Types = 1
-	EventSubCategory_ONT EventSubCategory_Types = 2
-	EventSubCategory_ONU EventSubCategory_Types = 3
-	EventSubCategory_NNI EventSubCategory_Types = 4
+	EventSubCategory_PON  EventSubCategory_Types = 0
+	EventSubCategory_OLT  EventSubCategory_Types = 1
+	EventSubCategory_ONT  EventSubCategory_Types = 2
+	EventSubCategory_ONU  EventSubCategory_Types = 3
+	EventSubCategory_NNI  EventSubCategory_Types = 4
+	EventSubCategory_NONE EventSubCategory_Types = 5
 )
 
 var EventSubCategory_Types_name = map[int32]string{
@@ -129,14 +130,16 @@
 	2: "ONT",
 	3: "ONU",
 	4: "NNI",
+	5: "NONE",
 }
 
 var EventSubCategory_Types_value = map[string]int32{
-	"PON": 0,
-	"OLT": 1,
-	"ONT": 2,
-	"ONU": 3,
-	"NNI": 4,
+	"PON":  0,
+	"OLT":  1,
+	"ONT":  2,
+	"ONU":  3,
+	"NNI":  4,
+	"NONE": 5,
 }
 
 func (x EventSubCategory_Types) String() string {
@@ -1149,85 +1152,86 @@
 func init() { proto.RegisterFile("voltha_protos/events.proto", fileDescriptor_e63e6c07044fd2c4) }
 
 var fileDescriptor_e63e6c07044fd2c4 = []byte{
-	// 1274 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdf, 0x6e, 0xdb, 0xb6,
-	0x17, 0xb6, 0xe4, 0xff, 0x47, 0x4e, 0xa2, 0xb0, 0xbf, 0xdf, 0xe6, 0xba, 0x5b, 0x9b, 0x7a, 0xd8,
-	0x10, 0xb4, 0xa8, 0x8c, 0x69, 0x05, 0x1a, 0xa4, 0x18, 0xb6, 0xd6, 0xf5, 0x1a, 0xa1, 0x8b, 0xed,
-	0x29, 0x4e, 0x80, 0xee, 0xc6, 0x60, 0x24, 0xc6, 0x11, 0x62, 0x5b, 0x02, 0x49, 0x1b, 0xcd, 0x03,
-	0xec, 0x7a, 0x0f, 0xb2, 0xe7, 0xd8, 0xdd, 0xde, 0x60, 0x18, 0xf6, 0x12, 0x7b, 0x80, 0x81, 0x7f,
-	0x64, 0x4b, 0x6e, 0x8a, 0x5e, 0x04, 0xbb, 0x12, 0x79, 0x78, 0x3e, 0x9e, 0xef, 0x7c, 0xe2, 0x39,
-	0x24, 0xb4, 0x96, 0xf1, 0x94, 0x5f, 0xe2, 0x71, 0x42, 0x63, 0x1e, 0xb3, 0x0e, 0x59, 0x92, 0x39,
-	0x67, 0x8e, 0x9c, 0xa1, 0x8a, 0x5a, 0x6b, 0x35, 0xf3, 0x3e, 0x33, 0xc2, 0xb1, 0xf2, 0x68, 0x7d,
-	0x36, 0x89, 0xe3, 0xc9, 0x94, 0x74, 0x70, 0x12, 0x75, 0xf0, 0x7c, 0x1e, 0x73, 0xcc, 0xa3, 0x78,
-	0xae, 0xf1, 0xad, 0x07, 0x7a, 0x55, 0xce, 0xce, 0x17, 0x17, 0x1d, 0x1e, 0xcd, 0x08, 0xe3, 0x78,
-	0x96, 0x68, 0x87, 0x8d, 0xe0, 0x41, 0x3c, 0x9b, 0xc5, 0x73, 0xb5, 0xd6, 0x7e, 0x0e, 0x3b, 0xdd,
-	0x78, 0x7e, 0x11, 0x4d, 0x7a, 0x82, 0xd2, 0xe8, 0x3a, 0x21, 0xed, 0x7d, 0x28, 0x8b, 0x2f, 0x43,
-	0x55, 0x28, 0xe2, 0x30, 0xb4, 0x0b, 0x08, 0xa0, 0x42, 0xc9, 0x2c, 0x5e, 0x12, 0xdb, 0x10, 0xe3,
-	0x45, 0x12, 0x62, 0x4e, 0x6c, 0xb3, 0x7d, 0x09, 0x56, 0x06, 0x8c, 0xbe, 0x86, 0x12, 0xbf, 0x4e,
-	0x48, 0xd3, 0xd8, 0x33, 0xf6, 0xb7, 0xdd, 0xcf, 0x1d, 0x15, 0xd6, 0xd9, 0xd8, 0xdf, 0x91, 0x9b,
-	0xfb, 0xd2, 0x15, 0x21, 0x28, 0x5d, 0x62, 0x76, 0xd9, 0x34, 0xf7, 0x8c, 0xfd, 0xba, 0x2f, 0xc7,
-	0xc2, 0x16, 0x62, 0x8e, 0x9b, 0x45, 0x65, 0x13, 0xe3, 0xf6, 0x23, 0x68, 0xbc, 0x49, 0xa2, 0x35,
-	0xc7, 0x56, 0xca, 0xb1, 0x0e, 0x65, 0x36, 0x8d, 0x02, 0x62, 0x17, 0x50, 0x05, 0x4c, 0xce, 0x6c,
-	0xa3, 0xfd, 0x9b, 0x09, 0xdb, 0xc7, 0x84, 0xd3, 0x28, 0x38, 0x26, 0x1c, 0xbf, 0xc2, 0x1c, 0xa3,
-	0xff, 0x41, 0x99, 0x47, 0x7c, 0xaa, 0xa8, 0xd5, 0x7d, 0x35, 0x41, 0xdb, 0x02, 0x20, 0x43, 0x1b,
-	0xbe, 0xc9, 0x19, 0x7a, 0x04, 0xbb, 0xd3, 0x78, 0x12, 0x05, 0x78, 0x3a, 0x0e, 0xc9, 0x32, 0x0a,
-	0xc8, 0x38, 0x0a, 0x35, 0x8b, 0x1d, 0xbd, 0xf0, 0x4a, 0xda, 0xbd, 0x10, 0xdd, 0x83, 0x3a, 0x23,
-	0x34, 0xc2, 0xd3, 0xf1, 0x3c, 0x6e, 0x96, 0xa4, 0x4f, 0x4d, 0x19, 0xfa, 0xb1, 0x58, 0x5c, 0x6f,
-	0x50, 0x56, 0x8b, 0x61, 0x8a, 0xfc, 0x16, 0xaa, 0x41, 0x3c, 0xe7, 0xe4, 0x1d, 0x6f, 0x56, 0xf6,
-	0x8a, 0xfb, 0x96, 0xfb, 0x45, 0x2a, 0x54, 0x9e, 0xb4, 0xd0, 0x4d, 0x78, 0xf5, 0xe6, 0x9c, 0x5e,
-	0xfb, 0x29, 0x46, 0xa8, 0xb3, 0x58, 0x44, 0x61, 0xb3, 0xaa, 0xd4, 0x11, 0xe3, 0xd6, 0x21, 0x34,
-	0xb2, 0xce, 0xc8, 0x86, 0xe2, 0x15, 0xb9, 0xd6, 0xc9, 0x8a, 0xa1, 0x10, 0x60, 0x89, 0xa7, 0x0b,
-	0xa2, 0x85, 0x56, 0x93, 0x43, 0xf3, 0xc0, 0x68, 0xff, 0x6a, 0x80, 0xad, 0x02, 0x9f, 0x09, 0xdb,
-	0x10, 0x47, 0x94, 0xa1, 0xef, 0xa0, 0x3a, 0x93, 0x36, 0xd6, 0x34, 0x24, 0xc7, 0x2f, 0xf3, 0x1c,
-	0xd7, 0xae, 0xda, 0xc0, 0x34, 0x4b, 0x8d, 0x12, 0x8c, 0xb2, 0x0b, 0x1f, 0x63, 0x64, 0x66, 0x19,
-	0xfd, 0x6e, 0xc0, 0xae, 0x02, 0x7b, 0xf3, 0x8b, 0x98, 0xce, 0xe4, 0x61, 0x47, 0x2e, 0xd4, 0x44,
-	0x45, 0xc8, 0x93, 0x21, 0xb6, 0xb1, 0xdc, 0x4f, 0x6e, 0xd6, 0xcd, 0x5f, 0xf9, 0xa1, 0xef, 0xd7,
-	0x69, 0x98, 0x32, 0x8d, 0xaf, 0xf2, 0x90, 0xcc, 0xfe, 0xff, 0x41, 0x1e, 0x7f, 0x19, 0x50, 0x4b,
-	0x0f, 0x2d, 0x72, 0x72, 0xb5, 0xd1, 0x4a, 0x79, 0x64, 0x0f, 0x75, 0xae, 0x30, 0xd6, 0x67, 0xd3,
-	0x94, 0x67, 0xf3, 0x10, 0x6a, 0x09, 0x25, 0x17, 0xd1, 0x3b, 0xc2, 0x9a, 0x45, 0x99, 0xcb, 0xfd,
-	0xcd, 0x3d, 0x9c, 0xa1, 0x76, 0x50, 0x39, 0xac, 0xfc, 0x5b, 0xa7, 0xb0, 0x95, 0x5b, 0xba, 0x21,
-	0x0b, 0x27, 0x9b, 0x85, 0xe5, 0x36, 0x3f, 0xf4, 0xbb, 0xb3, 0xf9, 0xfd, 0x62, 0x40, 0x3d, 0x8d,
-	0xed, 0xde, 0x22, 0x41, 0x55, 0x7c, 0x07, 0x00, 0xb2, 0x90, 0xc7, 0xba, 0xf6, 0x45, 0x8a, 0x77,
-	0x3f, 0xf8, 0xbb, 0xfc, 0xba, 0x74, 0x16, 0xff, 0xbb, 0xfd, 0x8f, 0x01, 0x96, 0xaa, 0x4b, 0x25,
-	0xf5, 0x03, 0xb0, 0x28, 0x61, 0xf1, 0x82, 0xaa, 0xfa, 0x53, 0x59, 0x42, 0x6a, 0xf2, 0x42, 0x51,
-	0xe7, 0xba, 0x3c, 0x65, 0x1f, 0x1e, 0xcf, 0xf1, 0x2c, 0x2d, 0x8c, 0x9d, 0x70, 0xbd, 0x51, 0x1f,
-	0xcf, 0x08, 0xda, 0x03, 0x2b, 0x24, 0x2c, 0xa0, 0x51, 0x22, 0xc2, 0xea, 0x6e, 0x90, 0x35, 0xa1,
-	0xc3, 0x75, 0x3d, 0x97, 0x24, 0xeb, 0xbd, 0x94, 0x75, 0x86, 0xd4, 0xcd, 0xc5, 0x7c, 0xab, 0xc2,
-	0xfd, 0xd3, 0x84, 0x9a, 0x3f, 0xec, 0xaa, 0x9c, 0x6d, 0x28, 0xd2, 0x24, 0x48, 0x81, 0x34, 0x09,
-	0xd0, 0x43, 0x68, 0xc4, 0x09, 0xa1, 0x52, 0x2d, 0x21, 0x83, 0xc2, 0x5b, 0x2b, 0x9b, 0x17, 0xa2,
-	0x26, 0x54, 0x19, 0xa1, 0x82, 0xa3, 0xce, 0x2b, 0x9d, 0xa2, 0xbb, 0x50, 0x63, 0x1c, 0x07, 0x57,
-	0x02, 0x58, 0xd2, 0x4b, 0x62, 0xee, 0x85, 0x9b, 0xea, 0x96, 0xdf, 0x53, 0x77, 0x43, 0xb1, 0xca,
-	0xfb, 0x8a, 0x3d, 0x5b, 0x2b, 0x56, 0x95, 0x8a, 0xad, 0xae, 0x8a, 0x34, 0x9f, 0x0f, 0xf4, 0xbe,
-	0x27, 0x50, 0x61, 0x1c, 0xf3, 0x05, 0x6b, 0xd6, 0xe4, 0x31, 0xfd, 0xbf, 0xa3, 0xef, 0xb2, 0x41,
-	0x9a, 0x95, 0x4f, 0x58, 0xe2, 0x6b, 0xa7, 0x5b, 0xa9, 0xbb, 0x84, 0x2d, 0xc9, 0xa4, 0x8b, 0x39,
-	0x99, 0xc4, 0xf4, 0xba, 0x4d, 0xd2, 0x1b, 0x67, 0x17, 0xb6, 0xba, 0x83, 0xe3, 0xe3, 0xd3, 0xbe,
-	0xd7, 0x7d, 0x31, 0xf2, 0x06, 0x7d, 0xbb, 0x80, 0x76, 0xc0, 0xea, 0xf5, 0xcf, 0x3c, 0x7f, 0xd0,
-	0x3f, 0xee, 0xf5, 0x47, 0xb6, 0x81, 0xb6, 0xa0, 0xde, 0xfb, 0xe9, 0xd4, 0x1b, 0xca, 0xa9, 0x89,
-	0x2c, 0xa8, 0x9e, 0xf4, 0xfc, 0x33, 0xaf, 0xdb, 0xb3, 0x8b, 0x68, 0x1b, 0x60, 0xe8, 0x0f, 0xba,
-	0xbd, 0x93, 0x13, 0xaf, 0xff, 0xda, 0x2e, 0xa1, 0x06, 0xd4, 0x4e, 0x7a, 0xdd, 0x53, 0xdf, 0x1b,
-	0xbd, 0xb5, 0xcb, 0xed, 0x23, 0xb0, 0x65, 0xdc, 0x93, 0xc5, 0xf9, 0x2a, 0xf4, 0xd3, 0xcc, 0x85,
-	0x3c, 0x94, 0x01, 0xab, 0x50, 0x1c, 0xfc, 0x28, 0x02, 0x89, 0x81, 0x0c, 0x21, 0x07, 0xa7, 0x76,
-	0x51, 0x0c, 0xfa, 0x7d, 0xcf, 0x2e, 0xb5, 0x2f, 0xa0, 0xbe, 0xbe, 0x2f, 0xdf, 0xa6, 0x5b, 0xd8,
-	0xd0, 0xe8, 0x0e, 0xfa, 0x3f, 0x78, 0xaf, 0xc7, 0xbd, 0x33, 0x41, 0xae, 0x20, 0xb8, 0xbe, 0x19,
-	0x7a, 0x7a, 0x6a, 0x08, 0x7a, 0xab, 0xa9, 0x6b, 0x9b, 0x02, 0xf0, 0xaa, 0x27, 0xa8, 0x6b, 0x8f,
-	0xa2, 0x00, 0xf8, 0xc3, 0xae, 0x9e, 0x96, 0xda, 0x7f, 0x9b, 0x60, 0xc9, 0x40, 0x47, 0x04, 0x87,
-	0x84, 0x8a, 0xc2, 0x5e, 0x55, 0x9d, 0x19, 0x85, 0xe8, 0x19, 0xd4, 0x02, 0x9d, 0x89, 0x94, 0x79,
-	0xdb, 0xbd, 0x97, 0xfe, 0xee, 0x9c, 0xc2, 0xba, 0x3b, 0xac, 0x9c, 0xd1, 0x0b, 0x68, 0xb0, 0xc5,
-	0xf9, 0x78, 0x05, 0x2e, 0x4a, 0xf0, 0xfd, 0x1c, 0x38, 0x23, 0x93, 0xc6, 0x5b, 0x6c, 0x6d, 0x42,
-	0x8f, 0x75, 0x53, 0x2a, 0x49, 0xe8, 0xa7, 0x39, 0xe8, 0x7b, 0x1d, 0xe9, 0x21, 0x34, 0xc4, 0x77,
-	0xbc, 0x24, 0x94, 0x89, 0x93, 0xab, 0x8e, 0xb6, 0x25, 0x6c, 0x67, 0xca, 0x84, 0x9e, 0x41, 0x9d,
-	0xe2, 0x88, 0x91, 0x70, 0xcc, 0x99, 0x3c, 0xd9, 0x96, 0xdb, 0x72, 0xd4, 0xf3, 0xcb, 0x49, 0x9f,
-	0x5f, 0xce, 0x28, 0x7d, 0x7e, 0xf9, 0x35, 0xe5, 0x3c, 0x62, 0xe8, 0xb9, 0xa8, 0x9a, 0x24, 0xa6,
-	0x5c, 0x41, 0xab, 0x1f, 0x85, 0x42, 0xea, 0x3e, 0x62, 0xed, 0x3f, 0x4c, 0x28, 0xab, 0x32, 0x7f,
-	0x0c, 0x95, 0x4b, 0xa9, 0xb2, 0xbe, 0x02, 0xef, 0xe4, 0x32, 0x52, 0x3f, 0xc0, 0xd7, 0x2e, 0xe8,
-	0x00, 0x1a, 0x81, 0x7c, 0x7a, 0xa9, 0x36, 0xa7, 0x5b, 0xfb, 0x9d, 0x1b, 0x9e, 0x65, 0x47, 0x05,
-	0xdf, 0x0a, 0x32, 0x0f, 0xb9, 0x0e, 0xd4, 0xaf, 0x92, 0x48, 0xc3, 0x8a, 0x12, 0x66, 0x6f, 0x36,
-	0xf4, 0xa3, 0x82, 0x5f, 0xbb, 0x4a, 0x6f, 0x37, 0x17, 0x60, 0x05, 0x70, 0xa5, 0xda, 0x96, 0xbb,
-	0xbb, 0x89, 0x70, 0x8f, 0x0a, 0x7e, 0xfd, 0x6a, 0x75, 0x61, 0x1c, 0x40, 0x23, 0xdb, 0x85, 0xa5,
-	0xdc, 0x19, 0x7a, 0x99, 0xe6, 0x29, 0xe8, 0x65, 0xfa, 0xb2, 0xa0, 0x47, 0x93, 0x40, 0xc3, 0x2a,
-	0x79, 0x7a, 0x69, 0x07, 0x11, 0xf4, 0x68, 0x12, 0xc8, 0xf1, 0xcb, 0x06, 0x80, 0xea, 0xf4, 0xe2,
-	0x5f, 0xbe, 0xec, 0xc1, 0x9d, 0x98, 0x4e, 0x9c, 0x38, 0x21, 0xf3, 0x20, 0xa6, 0xa1, 0x46, 0xfe,
-	0xec, 0x4c, 0x22, 0x7e, 0xb9, 0x38, 0x17, 0x2d, 0xa5, 0x93, 0xae, 0x75, 0xd4, 0xda, 0x13, 0xfd,
-	0x72, 0x5e, 0x3e, 0xed, 0x4c, 0x62, 0x6d, 0x3b, 0xaf, 0x48, 0xe3, 0x37, 0xff, 0x06, 0x00, 0x00,
-	0xff, 0xff, 0x7b, 0x2c, 0xa9, 0x18, 0xdb, 0x0b, 0x00, 0x00,
+	// 1282 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdb, 0x6e, 0xdb, 0x46,
+	0x13, 0x16, 0xa9, 0xf3, 0x50, 0xb6, 0xe9, 0xcd, 0xff, 0xb7, 0x8a, 0xd2, 0x26, 0x8e, 0x8a, 0x16,
+	0x46, 0x82, 0x50, 0x28, 0x5b, 0x20, 0x86, 0x83, 0x1e, 0x12, 0x85, 0x8d, 0x89, 0xd4, 0x94, 0x4a,
+	0xcb, 0x06, 0xd2, 0x1b, 0x61, 0x4d, 0xae, 0x65, 0xc2, 0x92, 0x48, 0x70, 0x57, 0x42, 0xfc, 0x00,
+	0xbd, 0xee, 0x83, 0xf4, 0x39, 0x7a, 0xd7, 0x37, 0x28, 0x8a, 0xbe, 0x44, 0x1f, 0xa0, 0xd8, 0x03,
+	0x25, 0x52, 0x71, 0x90, 0x0b, 0xa3, 0x57, 0xdc, 0x9d, 0x9d, 0x6f, 0xe7, 0x9b, 0x8f, 0x3b, 0xb3,
+	0x0b, 0x9d, 0x65, 0x3c, 0x65, 0x97, 0x78, 0x9c, 0xa4, 0x31, 0x8b, 0x69, 0x8f, 0x2c, 0xc9, 0x9c,
+	0x51, 0x4b, 0xcc, 0x50, 0x4d, 0xae, 0x75, 0xda, 0x45, 0x9f, 0x19, 0x61, 0x58, 0x7a, 0x74, 0x3e,
+	0x99, 0xc4, 0xf1, 0x64, 0x4a, 0x7a, 0x38, 0x89, 0x7a, 0x78, 0x3e, 0x8f, 0x19, 0x66, 0x51, 0x3c,
+	0x57, 0xf8, 0xce, 0x03, 0xb5, 0x2a, 0x66, 0xe7, 0x8b, 0x8b, 0x1e, 0x8b, 0x66, 0x84, 0x32, 0x3c,
+	0x4b, 0x94, 0xc3, 0x46, 0xf0, 0x20, 0x9e, 0xcd, 0xe2, 0xb9, 0x5c, 0xeb, 0x3e, 0x83, 0x9d, 0x7e,
+	0x3c, 0xbf, 0x88, 0x26, 0x0e, 0xa7, 0x34, 0xba, 0x4e, 0x48, 0x77, 0x1f, 0xaa, 0xfc, 0x4b, 0x51,
+	0x1d, 0xca, 0x38, 0x0c, 0xcd, 0x12, 0x02, 0xa8, 0xa5, 0x64, 0x16, 0x2f, 0x89, 0xa9, 0xf1, 0xf1,
+	0x22, 0x09, 0x31, 0x23, 0xa6, 0xde, 0xbd, 0x04, 0x23, 0x07, 0x46, 0x5f, 0x42, 0x85, 0x5d, 0x27,
+	0xa4, 0xad, 0xed, 0x69, 0xfb, 0xdb, 0xf6, 0xa7, 0x96, 0x0c, 0x6b, 0x6d, 0xec, 0x6f, 0x89, 0xcd,
+	0x7d, 0xe1, 0x8a, 0x10, 0x54, 0x2e, 0x31, 0xbd, 0x6c, 0xeb, 0x7b, 0xda, 0x7e, 0xd3, 0x17, 0x63,
+	0x6e, 0x0b, 0x31, 0xc3, 0xed, 0xb2, 0xb4, 0xf1, 0x71, 0xf7, 0x11, 0xb4, 0x5e, 0x27, 0xd1, 0x9a,
+	0x63, 0x27, 0xe3, 0xd8, 0x84, 0x2a, 0x9d, 0x46, 0x01, 0x31, 0x4b, 0xa8, 0x06, 0x3a, 0xa3, 0xa6,
+	0xd6, 0xfd, 0x4d, 0x87, 0xed, 0x63, 0xc2, 0xd2, 0x28, 0x38, 0x26, 0x0c, 0xbf, 0xc4, 0x0c, 0xa3,
+	0xff, 0x41, 0x95, 0x45, 0x6c, 0x2a, 0xa9, 0x35, 0x7d, 0x39, 0x41, 0xdb, 0x1c, 0x20, 0x42, 0x6b,
+	0xbe, 0xce, 0x28, 0x7a, 0x04, 0xbb, 0xd3, 0x78, 0x12, 0x05, 0x78, 0x3a, 0x0e, 0xc9, 0x32, 0x0a,
+	0xc8, 0x38, 0x0a, 0x15, 0x8b, 0x1d, 0xb5, 0xf0, 0x52, 0xd8, 0xdd, 0x10, 0xdd, 0x83, 0x26, 0x25,
+	0x69, 0x84, 0xa7, 0xe3, 0x79, 0xdc, 0xae, 0x08, 0x9f, 0x86, 0x34, 0x78, 0x31, 0x5f, 0x5c, 0x6f,
+	0x50, 0x95, 0x8b, 0x61, 0x86, 0xfc, 0x06, 0xea, 0x41, 0x3c, 0x67, 0xe4, 0x2d, 0x6b, 0xd7, 0xf6,
+	0xca, 0xfb, 0x86, 0xfd, 0x59, 0x26, 0x54, 0x91, 0x34, 0xd7, 0x8d, 0x7b, 0x39, 0x73, 0x96, 0x5e,
+	0xfb, 0x19, 0x86, 0xab, 0xb3, 0x58, 0x44, 0x61, 0xbb, 0x2e, 0xd5, 0xe1, 0xe3, 0xce, 0x21, 0xb4,
+	0xf2, 0xce, 0xc8, 0x84, 0xf2, 0x15, 0xb9, 0x56, 0xc9, 0xf2, 0x21, 0x17, 0x60, 0x89, 0xa7, 0x0b,
+	0xa2, 0x84, 0x96, 0x93, 0x43, 0xfd, 0x40, 0xeb, 0xfe, 0xaa, 0x81, 0x29, 0x03, 0x9f, 0x71, 0xdb,
+	0x10, 0x47, 0x29, 0x45, 0xdf, 0x41, 0x7d, 0x26, 0x6c, 0xb4, 0xad, 0x09, 0x8e, 0x9f, 0x17, 0x39,
+	0xae, 0x5d, 0x95, 0x81, 0x2a, 0x96, 0x0a, 0xc5, 0x19, 0xe5, 0x17, 0x3e, 0xc4, 0x48, 0xcf, 0x33,
+	0xfa, 0x5d, 0x83, 0x5d, 0x09, 0x76, 0xe7, 0x17, 0x71, 0x3a, 0x13, 0x87, 0x1d, 0xd9, 0xd0, 0xe0,
+	0x15, 0x21, 0x4e, 0x06, 0xdf, 0xc6, 0xb0, 0x3f, 0xba, 0x59, 0x37, 0x7f, 0xe5, 0x87, 0xbe, 0x5f,
+	0xa7, 0xa1, 0x8b, 0x34, 0xbe, 0x28, 0x42, 0x72, 0xfb, 0xff, 0x07, 0x79, 0xfc, 0xa5, 0x41, 0x23,
+	0x3b, 0xb4, 0xc8, 0x2a, 0xd4, 0x46, 0x27, 0xe3, 0x91, 0x3f, 0xd4, 0x85, 0xc2, 0x58, 0x9f, 0x4d,
+	0x5d, 0x9c, 0xcd, 0x43, 0x68, 0x24, 0x29, 0xb9, 0x88, 0xde, 0x12, 0xda, 0x2e, 0x8b, 0x5c, 0xee,
+	0x6f, 0xee, 0x61, 0x0d, 0x95, 0x83, 0xcc, 0x61, 0xe5, 0xdf, 0x39, 0x85, 0xad, 0xc2, 0xd2, 0x0d,
+	0x59, 0x58, 0xf9, 0x2c, 0x0c, 0xbb, 0xfd, 0xbe, 0xdf, 0x9d, 0xcf, 0xef, 0x17, 0x0d, 0x9a, 0x59,
+	0x6c, 0xfb, 0x16, 0x09, 0xca, 0xe2, 0x3b, 0x00, 0x10, 0x85, 0x3c, 0x56, 0xb5, 0xcf, 0x53, 0xbc,
+	0xfb, 0xde, 0xdf, 0xe5, 0x37, 0x85, 0x33, 0xff, 0xdf, 0xdd, 0x7f, 0x34, 0x30, 0x64, 0x5d, 0x4a,
+	0xa9, 0x1f, 0x80, 0x91, 0x12, 0x1a, 0x2f, 0x52, 0x59, 0x7f, 0x32, 0x4b, 0xc8, 0x4c, 0x6e, 0xc8,
+	0xeb, 0x5c, 0x95, 0xa7, 0xe8, 0xc3, 0xe3, 0x39, 0x9e, 0x65, 0x85, 0xb1, 0x13, 0xae, 0x37, 0xf2,
+	0xf0, 0x8c, 0xa0, 0x3d, 0x30, 0x42, 0x42, 0x83, 0x34, 0x4a, 0x78, 0x58, 0xd5, 0x0d, 0xf2, 0x26,
+	0x74, 0xb8, 0xae, 0xe7, 0x8a, 0x60, 0xbd, 0x97, 0xb1, 0xce, 0x91, 0xba, 0xb9, 0x98, 0x6f, 0x55,
+	0xb8, 0x7f, 0xea, 0xd0, 0xf0, 0x87, 0x7d, 0x99, 0xb3, 0x09, 0xe5, 0x34, 0x09, 0x32, 0x60, 0x9a,
+	0x04, 0xe8, 0x21, 0xb4, 0xe2, 0x84, 0xa4, 0x42, 0x2d, 0x2e, 0x83, 0xc4, 0x1b, 0x2b, 0x9b, 0x1b,
+	0xa2, 0x36, 0xd4, 0x29, 0x49, 0x39, 0x47, 0x95, 0x57, 0x36, 0x45, 0x77, 0xa1, 0x41, 0x19, 0x0e,
+	0xae, 0x38, 0xb0, 0xa2, 0x96, 0xf8, 0xdc, 0x0d, 0x37, 0xd5, 0xad, 0xbe, 0xa3, 0xee, 0x86, 0x62,
+	0xb5, 0x77, 0x15, 0x7b, 0xba, 0x56, 0xac, 0x2e, 0x14, 0x5b, 0x5d, 0x15, 0x59, 0x3e, 0xef, 0xe9,
+	0x7d, 0x4f, 0xa0, 0x46, 0x19, 0x66, 0x0b, 0xda, 0x6e, 0x88, 0x63, 0xfa, 0x7f, 0x4b, 0xdd, 0x65,
+	0x83, 0x2c, 0x2b, 0x9f, 0xd0, 0xc4, 0x57, 0x4e, 0xb7, 0x52, 0x77, 0x09, 0x5b, 0x82, 0x49, 0x1f,
+	0x33, 0x32, 0x89, 0xd3, 0xeb, 0x2e, 0xc9, 0x6e, 0x9c, 0x5d, 0xd8, 0xea, 0x0f, 0x8e, 0x8f, 0x4f,
+	0x3d, 0xb7, 0xff, 0x7c, 0xe4, 0x0e, 0x3c, 0xb3, 0x84, 0x76, 0xc0, 0x70, 0xbc, 0x33, 0xd7, 0x1f,
+	0x78, 0xc7, 0x8e, 0x37, 0x32, 0x35, 0xb4, 0x05, 0x4d, 0xe7, 0xa7, 0x53, 0x77, 0x28, 0xa6, 0x3a,
+	0x32, 0xa0, 0x7e, 0xe2, 0xf8, 0x67, 0x6e, 0xdf, 0x31, 0xcb, 0x68, 0x1b, 0x60, 0xe8, 0x0f, 0xfa,
+	0xce, 0xc9, 0x89, 0xeb, 0xbd, 0x32, 0x2b, 0xa8, 0x05, 0x8d, 0x13, 0xa7, 0x7f, 0xea, 0xbb, 0xa3,
+	0x37, 0x66, 0xb5, 0xeb, 0x83, 0x29, 0xe2, 0x9e, 0x2c, 0xce, 0x57, 0xa1, 0xbf, 0xcd, 0x5d, 0xc8,
+	0x43, 0x11, 0xb0, 0x0e, 0xe5, 0xc1, 0x8f, 0x3c, 0x10, 0x1f, 0x88, 0x10, 0x62, 0x70, 0x6a, 0x96,
+	0xf9, 0xc0, 0xf3, 0x5c, 0xb3, 0x82, 0x1a, 0x50, 0xf1, 0x06, 0x9e, 0x63, 0x56, 0xbb, 0x17, 0xd0,
+	0x5c, 0xdf, 0x9c, 0x6f, 0xb2, 0xcd, 0x4c, 0x68, 0xf5, 0x07, 0xde, 0x0f, 0xee, 0xab, 0xb1, 0x73,
+	0xc6, 0x69, 0x96, 0x38, 0xeb, 0xd7, 0x43, 0x57, 0x4d, 0x35, 0x4e, 0x74, 0x35, 0xb5, 0x4d, 0x9d,
+	0x03, 0x5e, 0x3a, 0x3c, 0x09, 0xe5, 0x51, 0xe6, 0x00, 0x7f, 0xd8, 0x57, 0xd3, 0x4a, 0xf7, 0x6f,
+	0x1d, 0x0c, 0x11, 0xe8, 0x88, 0xe0, 0x90, 0xa4, 0xbc, 0xc4, 0x57, 0xf5, 0xa7, 0x47, 0x21, 0x7a,
+	0x0a, 0x8d, 0x40, 0xe5, 0x24, 0x04, 0xdf, 0xb6, 0xef, 0x65, 0x3f, 0xbe, 0xa0, 0xb5, 0xea, 0x13,
+	0x2b, 0x67, 0xf4, 0x1c, 0x5a, 0x74, 0x71, 0x3e, 0x5e, 0x81, 0xcb, 0x02, 0x7c, 0xbf, 0x00, 0xce,
+	0x09, 0xa6, 0xf0, 0x06, 0x5d, 0x9b, 0xd0, 0x63, 0xd5, 0x9e, 0x2a, 0x02, 0xfa, 0x71, 0x01, 0xfa,
+	0x4e, 0x6f, 0x7a, 0x08, 0x2d, 0xfe, 0x1d, 0x2f, 0x49, 0x4a, 0xf9, 0x19, 0x96, 0x87, 0xdc, 0xe0,
+	0xb6, 0x33, 0x69, 0x42, 0x4f, 0xa1, 0x99, 0xe2, 0x88, 0x92, 0x70, 0xcc, 0xa8, 0x38, 0xe3, 0x86,
+	0xdd, 0xb1, 0xe4, 0x43, 0xcc, 0xca, 0x1e, 0x62, 0xd6, 0x28, 0x7b, 0x88, 0xf9, 0x0d, 0xe9, 0x3c,
+	0xa2, 0xe8, 0x19, 0xaf, 0x9f, 0x24, 0x4e, 0x99, 0x84, 0xd6, 0x3f, 0x08, 0x85, 0xcc, 0x7d, 0x44,
+	0xbb, 0x7f, 0xe8, 0x50, 0x95, 0x05, 0xff, 0x18, 0x6a, 0x97, 0x42, 0x65, 0x75, 0x19, 0xde, 0x29,
+	0x64, 0x24, 0x7f, 0x80, 0xaf, 0x5c, 0xd0, 0x01, 0xb4, 0x02, 0xf1, 0x08, 0x93, 0x0d, 0x4f, 0x35,
+	0xf9, 0x3b, 0x37, 0x3c, 0xd0, 0x8e, 0x4a, 0xbe, 0x11, 0xe4, 0x9e, 0x74, 0x3d, 0x68, 0x5e, 0x25,
+	0x91, 0x82, 0x95, 0x05, 0xcc, 0xdc, 0x6c, 0xed, 0x47, 0x25, 0xbf, 0x71, 0x95, 0xdd, 0x73, 0x36,
+	0xc0, 0x0a, 0x60, 0x0b, 0xb5, 0x0d, 0x7b, 0x77, 0x13, 0x61, 0x1f, 0x95, 0xfc, 0xe6, 0xd5, 0xea,
+	0xea, 0x38, 0x80, 0x56, 0xbe, 0x1f, 0x0b, 0xb9, 0x73, 0xf4, 0x72, 0x6d, 0x94, 0xd3, 0xcb, 0x75,
+	0x68, 0x4e, 0x2f, 0x4d, 0x02, 0x05, 0xab, 0x15, 0xe9, 0x65, 0xbd, 0x84, 0xd3, 0x4b, 0x93, 0x40,
+	0x8c, 0x5f, 0xb4, 0x00, 0x64, 0xcf, 0xe7, 0xff, 0xf2, 0x85, 0x03, 0x77, 0xe2, 0x74, 0x62, 0xc5,
+	0x09, 0x99, 0x07, 0x71, 0x1a, 0x2a, 0xe4, 0xcf, 0xd6, 0x24, 0x62, 0x97, 0x8b, 0x73, 0xde, 0x5c,
+	0x7a, 0xd9, 0x5a, 0x4f, 0xae, 0x3d, 0x51, 0x6f, 0xe8, 0xe5, 0xd7, 0xbd, 0x49, 0xac, 0x6c, 0xe7,
+	0x35, 0x61, 0xfc, 0xea, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0xd5, 0xe2, 0x3b, 0xe5, 0x0b,
+	0x00, 0x00,
 }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 155b102..5448a90 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -7,6 +7,8 @@
 github.com/aead/cmac/aes
 # github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878
 github.com/armon/go-metrics
+# github.com/boguslaw-wojcik/crc32a v1.0.0
+github.com/boguslaw-wojcik/crc32a
 # github.com/bsm/sarama-cluster v2.1.15+incompatible
 github.com/bsm/sarama-cluster
 # github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72
@@ -74,7 +76,7 @@
 # github.com/opencord/omci-lib-go v0.15.0
 github.com/opencord/omci-lib-go
 github.com/opencord/omci-lib-go/generated
-# github.com/opencord/voltha-lib-go/v4 v4.0.6
+# github.com/opencord/voltha-lib-go/v4 v4.0.8
 github.com/opencord/voltha-lib-go/v4/pkg/adapters
 github.com/opencord/voltha-lib-go/v4/pkg/adapters/adapterif
 github.com/opencord/voltha-lib-go/v4/pkg/adapters/common
@@ -89,7 +91,7 @@
 github.com/opencord/voltha-lib-go/v4/pkg/probe
 github.com/opencord/voltha-lib-go/v4/pkg/techprofile
 github.com/opencord/voltha-lib-go/v4/pkg/version
-# github.com/opencord/voltha-protos/v4 v4.0.11
+# github.com/opencord/voltha-protos/v4 v4.0.12
 github.com/opencord/voltha-protos/v4/go/common
 github.com/opencord/voltha-protos/v4/go/ext/config
 github.com/opencord/voltha-protos/v4/go/extension