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/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})