Omci receive workaround for Adtran OLT-Sim, some preparations for OnuSwUpgrade

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: Iceb5c2309d65bf2893105c7701125606ef9c095b
diff --git a/internal/pkg/onuadaptercore/adapter_download_manager.go b/internal/pkg/onuadaptercore/adapter_download_manager.go
new file mode 100644
index 0000000..660c1fe
--- /dev/null
+++ b/internal/pkg/onuadaptercore/adapter_download_manager.go
@@ -0,0 +1,77 @@
+/*
+ * 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"
+	"errors"
+	"sync"
+
+	//"time"
+
+	"github.com/opencord/voltha-protos/v4/go/voltha"
+
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+// ### downloadToAdapter related definitions  ####
+
+//not yet defined to go with sca..., later also some configure options ??
+//const defaultDownloadTimeout = 60 // (?) Seconds
+//const localImgPath = "/home/lcui/work/tmp"
+
+// ### downloadToAdapter  			    - end ####
+
+//adapterDownloadManager structure holds information needed for downloading to and storing images within the adapter
+type adapterDownloadManager struct {
+	mutexDownloadImageDsc sync.RWMutex
+	downloadImageDscSlice []*voltha.ImageDownload
+}
+
+//newAdapterDownloadManager constructor returns a new instance of a adapterDownloadManager
+//mib_db (as well as not inluded alarm_db not really used in this code? VERIFY!!)
+func newAdapterDownloadManager(ctx context.Context) *adapterDownloadManager {
+	logger.Debug(ctx, "init-adapterDownloadManager")
+	var localDnldMgr adapterDownloadManager
+	localDnldMgr.downloadImageDscSlice = make([]*voltha.ImageDownload, 0)
+
+	return &localDnldMgr
+}
+
+//imageExists returns true if the requested image already exists within the adapter
+func (dm *adapterDownloadManager) imageExists(ctx context.Context, apImageDsc *voltha.ImageDownload) bool {
+	logger.Debugw(ctx, "checking on existence of the image", 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)
+			return true
+		}
+	}
+	//image not found (by 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.Debugw(ctx, "image download requested", log.Fields{"image-name": apImageDsc.Name})
+	//so far just return error
+	return errors.New("could not start downloading")
+}
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index de71501..0e0c1af 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -909,6 +909,13 @@
 	return nil
 }
 
+//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{
+		"device-id": dh.deviceID, "image-name": (*apImageDsc).Name})
+	return fmt.Errorf("onuSwUpgrade not yet implemented in deviceHandler: %s", dh.deviceID)
+}
+
 //  deviceHandler methods that implement the adapters interface requests## end #########
 // #####################################################################################
 
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 6d336f4..cd91e77 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -61,6 +61,20 @@
 
 const unusedTcontAllocID = uint16(0xFFFF) //common unused AllocId for G.984 and G.987 systems
 
+const cOmciBaseMessageTrailerLen = 40
+
+// tOmciReceiveError - enum type for detected problems/errors in the received OMCI message (format)
+type tOmciReceiveError uint8
+
+const (
+	// cOmciMessageReceiveNoError - default start state
+	cOmciMessageReceiveNoError tOmciReceiveError = iota
+	// Error indication wrong trailer length within the message
+	cOmciMessageReceiveErrorTrailerLen
+	// Error indication missing trailer within the message
+	cOmciMessageReceiveErrorMissTrailer
+)
+
 // ### OMCI related definitions - end
 
 //callbackPairEntry to be used for OMCI send/receive correlation
@@ -91,9 +105,8 @@
 	coreProxy          adapterif.CoreProxy
 	adapterProxy       adapterif.AdapterProxy
 	supportExtMsg      bool
-	//txRequest
-	//rxResponse
-	//pendingRequest
+	rxOmciFrameError   tOmciReceiveError
+
 	txFrames, txOnuFrames                uint32
 	rxFrames, rxOnuFrames, rxOnuDiscards uint32
 
@@ -136,6 +149,7 @@
 	omciCC.coreProxy = coreProxy
 	omciCC.adapterProxy = adapterProxy
 	omciCC.supportExtMsg = false
+	omciCC.rxOmciFrameError = cOmciMessageReceiveNoError
 	omciCC.txFrames = 0
 	omciCC.txOnuFrames = 0
 	omciCC.rxFrames = 0
@@ -173,6 +187,7 @@
 	//reset control values
 	oo.uploadSequNo = 0
 	oo.uploadNoOfCmds = 0
+	oo.rxOmciFrameError = cOmciMessageReceiveNoError
 	//reset the stats counter - which might be topic of discussion ...
 	oo.txFrames = 0
 	oo.txOnuFrames = 0
@@ -239,16 +254,35 @@
 	//logger.Debugw(ctx,"cc-receive-omci-message", log.Fields{"RxOmciMessage-x2s": hex.EncodeToString(rxMsg)})
 	if len(rxMsg) >= 44 { // then it should normally include the BaseFormat trailer Len
 		// NOTE: autocorrection only valid for OmciBaseFormat, which is not specifically verified here!!!
-		//  (am extendedFormat message could be destroyed this way!)
+		//  (an extendedFormat message could be destroyed this way!)
 		trailerLenData := rxMsg[42:44]
 		trailerLen := binary.BigEndian.Uint16(trailerLenData)
 		//logger.Debugw(ctx,"omci-received-trailer-len", log.Fields{"Length": trailerLen})
-		if trailerLen != 40 { // invalid base Format entry -> autocorrect
-			binary.BigEndian.PutUint16(rxMsg[42:44], 40)
-			logger.Debug(ctx, "cc-corrected-omci-message: trailer len inserted")
+		if trailerLen != cOmciBaseMessageTrailerLen { // invalid base Format entry -> autocorrect
+			binary.BigEndian.PutUint16(rxMsg[42:44], cOmciBaseMessageTrailerLen)
+			if oo.rxOmciFrameError != cOmciMessageReceiveErrorTrailerLen {
+				//do just one error log, expectation is: if seen once it should appear regularly - avoid to many log entries
+				logger.Errorw(ctx, "wrong omci-message trailer length: trailer len auto-corrected",
+					log.Fields{"trailer-length": trailerLen, "device-id": oo.deviceID})
+				oo.rxOmciFrameError = cOmciMessageReceiveErrorTrailerLen
+			}
+		}
+	} else if len(rxMsg) >= cOmciBaseMessageTrailerLen { // workaround for Adtran OLT Sim, which currently does not send trailer bytes at all!
+		// NOTE: autocorrection only valid for OmciBaseFormat, which is not specifically verified here!!!
+		//  (an extendedFormat message could be destroyed this way!)
+		// extend/overwrite with trailer
+		trailer := make([]byte, 8)
+		binary.BigEndian.PutUint16(trailer[2:], cOmciBaseMessageTrailerLen) //set the defined baseline length
+		rxMsg = append(rxMsg[:cOmciBaseMessageTrailerLen], trailer...)
+		if oo.rxOmciFrameError != cOmciMessageReceiveErrorMissTrailer {
+			//do just one error log, expectation is: if seen once it should appear regularly - avoid to many log entries
+			logger.Errorw(ctx, "omci-message to short to include trailer len: trailer auto-corrected (added)",
+				log.Fields{"message-length": len(rxMsg), "device-id": oo.deviceID})
+			oo.rxOmciFrameError = cOmciMessageReceiveErrorMissTrailer
 		}
 	} else {
-		logger.Errorw(ctx, "received omci-message too small for OmciBaseFormat - abort", log.Fields{"Length": len(rxMsg)})
+		logger.Errorw(ctx, "received omci-message too small for OmciBaseFormat - abort",
+			log.Fields{"Length": len(rxMsg), "device-id": oo.deviceID})
 		return fmt.Errorf("rxOmciMessage too small for BaseFormat %s", oo.deviceID)
 	}
 
@@ -291,6 +325,7 @@
 		if isResponseWithMibDataSync(omciMsg.MessageType) {
 			oo.pOnuDeviceEntry.incrementMibDataSync(ctx)
 		}
+
 		// having posted the response the request is regarded as 'done'
 		delete(oo.rxSchedulerMap, omciMsg.TransactionID)
 		oo.mutexRxSchedMap.Unlock()
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index 58b1771..f670437 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -32,6 +32,7 @@
 	"github.com/opencord/voltha-lib-go/v4/pkg/events/eventif"
 	"github.com/opencord/voltha-lib-go/v4/pkg/kafka"
 	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+	"github.com/opencord/voltha-protos/v4/go/extension"
 	ic "github.com/opencord/voltha-protos/v4/go/inter_container"
 	"github.com/opencord/voltha-protos/v4/go/openflow_13"
 	oop "github.com/opencord/voltha-protos/v4/go/openolt"
@@ -66,6 +67,7 @@
 	//GrpcTimeoutInterval         time.Duration
 	pSupportedFsms             *OmciDeviceFsms
 	maxTimeoutInterAdapterComm time.Duration
+	pDownloadManager           *adapterDownloadManager
 }
 
 //NewOpenONUAC returns a new instance of OpenONU_AC
@@ -114,13 +116,15 @@
 		},
 	}
 
+	openOnuAc.pDownloadManager = newAdapterDownloadManager(ctx)
+
 	return &openOnuAc
 }
 
 //Start starts (logs) the adapter
 func (oo *OpenONUAC) Start(ctx context.Context) error {
 	logger.Info(ctx, "starting-openonu-adapter")
-	logger.Info(ctx, "openonu-adapter-started")
+
 	return nil
 }
 
@@ -438,9 +442,17 @@
 	return errors.New("unImplemented")
 }
 
-//Download_image unimplemented
-func (oo *OpenONUAC) Download_image(ctx context.Context, device *voltha.Device, request *voltha.ImageDownload) (*voltha.ImageDownload, error) {
-	return nil, errors.New("unImplemented")
+//Download_image according to download image indications as given in apRequest
+func (oo *OpenONUAC) Download_image(ctx context.Context, device *voltha.Device, apRequest *voltha.ImageDownload) (*voltha.ImageDownload, error) {
+	if !oo.pDownloadManager.imageExists(ctx, apRequest) {
+		logger.Debugw(ctx, "start image download", log.Fields{"image-description": apRequest})
+		// Download_image is not supposed to be blocking, anyway let's call the DownloadManager still synchronously to detect 'fast' problems
+		// the download itself is later done in background
+		err := oo.pDownloadManager.startDownload(ctx, apRequest)
+		return apRequest, err
+	}
+	// image already exists
+	return apRequest, nil
 }
 
 //Get_image_download_status unimplemented
@@ -454,8 +466,13 @@
 }
 
 //Activate_image_update unimplemented
-func (oo *OpenONUAC) Activate_image_update(ctx context.Context, device *voltha.Device, request *voltha.ImageDownload) (*voltha.ImageDownload, error) {
-	return nil, errors.New("unImplemented")
+func (oo *OpenONUAC) Activate_image_update(ctx context.Context, device *voltha.Device, apRequest *voltha.ImageDownload) (*voltha.ImageDownload, error) {
+	if handler := oo.getDeviceHandler(ctx, device.Id, false); handler != nil {
+		err := handler.doOnuSwUpgrade(ctx, apRequest)
+		return apRequest, err
+	}
+	logger.Warnw(ctx, "no handler found for Onu image activation", log.Fields{"device-id": device.Id})
+	return apRequest, fmt.Errorf(fmt.Sprintf("handler-not-found-%s", device.Id))
 }
 
 //Revert_image_update unimplemented
@@ -489,5 +506,10 @@
 	return nil, errors.New("unImplemented")
 }
 
+//Single_get_value_request as needed by voltha-lib-go update to 4.0.xx?
+func (oo *OpenONUAC) Single_get_value_request(ctx context.Context, request extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
+	return nil, errors.New("unImplemented")
+}
+
 // Adapter interface required methods ################ end #########
 // #################################################################