VOL-3608 Support of Get External OMCI Attribute values - GetOnuUniInfoResponse in golang OpenONU adapter

Change-Id: I8c944d66e9ad71a49b817814ff4f130ebdcc17c9
diff --git a/internal/pkg/onuadaptercore/uniportstatus.go b/internal/pkg/onuadaptercore/uniportstatus.go
new file mode 100644
index 0000000..ba4bdf0
--- /dev/null
+++ b/internal/pkg/onuadaptercore/uniportstatus.go
@@ -0,0 +1,164 @@
+/*
+ * 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"
+	"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/extension"
+	"time"
+)
+
+const (
+	uniStatusTimeout = 3
+	adminState       = "AdministrativeState"
+	operationalState = "OperationalState"
+	configInd        = "ConfigurationInd"
+)
+
+//UniPortStatus implements methods to get uni port status info
+type UniPortStatus struct {
+	omciRespChn       chan Message
+	pOmiCC            *omciCC
+	pLastTxMeInstance *me.ManagedEntity
+}
+
+//NewUniPortStatus creates a new instance of UniPortStatus
+func NewUniPortStatus(pOmicc *omciCC) *UniPortStatus {
+	return &UniPortStatus{
+		omciRespChn: make(chan Message),
+		pOmiCC:      pOmicc,
+	}
+
+}
+
+func (portStatus *UniPortStatus) getUniPortStatus(ctx context.Context, uniIdx uint32) *extension.SingleGetValueResponse {
+	for _, uniPort := range portStatus.pOmiCC.pBaseDeviceHandler.uniEntityMap {
+
+		if uniPort.uniID == uint8(uniIdx) && uniPort.portType == uniPPTP {
+
+			requestedAttributes := me.AttributeValueMap{adminState: 0, operationalState: 0, configInd: 0}
+			if meInstance := portStatus.pOmiCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, uniPort.entityID, requestedAttributes, ConstDefaultOmciTimeout, true, portStatus.omciRespChn); meInstance != nil {
+				portStatus.pLastTxMeInstance = meInstance
+
+				//verify response
+				return portStatus.waitforgetUniPortStatus(ctx, meInstance)
+			}
+		}
+	}
+	logger.Errorw(ctx, "getUniPortStatus uniIdx is not valid", log.Fields{"uniIdx": uniIdx})
+	return postUniStatusErrResponse(extension.GetValueResponse_INVALID_PORT_TYPE)
+}
+
+func (portStatus *UniPortStatus) waitforgetUniPortStatus(ctx context.Context, apMeInstance *me.ManagedEntity) *extension.SingleGetValueResponse {
+
+	select {
+	// maybe be also some outside cancel (but no context modeled for the moment ...)
+	case <-ctx.Done():
+		logger.Errorf(ctx, "waitforgetUniPortStatus Context done")
+		return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+	case <-time.After(uniStatusTimeout * time.Second):
+		logger.Errorf(ctx, "waitforgetUniPortStatus  timeout")
+		return postUniStatusErrResponse(extension.GetValueResponse_TIMEOUT)
+
+	case omciMsg := <-portStatus.omciRespChn:
+		if omciMsg.Type != OMCI {
+			return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+		}
+		msg, _ := omciMsg.Data.(OmciMessage)
+		return portStatus.processGetUnitStatusResp(ctx, msg)
+	}
+
+}
+
+func (portStatus *UniPortStatus) processGetUnitStatusResp(ctx context.Context, msg OmciMessage) *extension.SingleGetValueResponse {
+	logger.Debugw(ctx, "processGetUniStatusResp:", log.Fields{"msg.Omci.MessageType": msg.OmciMsg.MessageType,
+		"msg.OmciMsg.TransactionID": msg.OmciMsg.TransactionID, "DeviceIdentfier": msg.OmciMsg.DeviceIdentifier})
+
+	if msg.OmciMsg.MessageType != omci.GetResponseType {
+		logger.Debugw(ctx, "processGetUniStatusResp error", log.Fields{"incorrect RespType": msg.OmciMsg.MessageType,
+			"expected": omci.GetResponseType})
+		return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+	}
+
+	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
+	if msgLayer == nil {
+		logger.Errorf(ctx, "processGetUniStatusResp omci Msg layer not found - ")
+		return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+
+	}
+	msgObj, msgOk := msgLayer.(*omci.GetResponse)
+	if !msgOk {
+		logger.Errorf(ctx, "processGetUniStatusResp omci msgObj layer could not be found ")
+		return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+
+	}
+
+	if msgObj.Result != me.Success {
+		return postUniStatusErrResponse(extension.GetValueResponse_INTERNAL_ERROR)
+	}
+	meAttributes := msgObj.Attributes
+
+	singleValResp := extension.SingleGetValueResponse{
+		Response: &extension.GetValueResponse{
+			Status: extension.GetValueResponse_OK,
+			Response: &extension.GetValueResponse_UniInfo{
+				UniInfo: &extension.GetOnuUniInfoResponse{},
+			},
+		},
+	}
+	if meAttributes[operationalState].(uint8) == 0 {
+		singleValResp.Response.GetUniInfo().OperState = extension.GetOnuUniInfoResponse_ENABLED
+	} else if meAttributes[operationalState].(uint8) == 1 {
+		singleValResp.Response.GetUniInfo().OperState = extension.GetOnuUniInfoResponse_DISABLED
+	} else {
+		singleValResp.Response.GetUniInfo().OperState = extension.GetOnuUniInfoResponse_OPERSTATE_UNDEFINED
+	}
+
+	if meAttributes[adminState].(uint8) == 0 {
+		singleValResp.Response.GetUniInfo().AdmState = extension.GetOnuUniInfoResponse_UNLOCKED
+	} else if meAttributes[adminState].(uint8) == 1 {
+		singleValResp.Response.GetUniInfo().AdmState = extension.GetOnuUniInfoResponse_LOCKED
+	} else {
+		singleValResp.Response.GetUniInfo().AdmState = extension.GetOnuUniInfoResponse_ADMSTATE_UNDEFINED
+	}
+	configIndMap := map[uint8]extension.GetOnuUniInfoResponse_ConfigurationInd{
+		0:  0,
+		1:  extension.GetOnuUniInfoResponse_TEN_BASE_T_FDX,
+		2:  extension.GetOnuUniInfoResponse_HUNDRED_BASE_T_FDX,
+		3:  extension.GetOnuUniInfoResponse_GIGABIT_ETHERNET_FDX,
+		4:  extension.GetOnuUniInfoResponse_TEN_G_ETHERNET_FDX,
+		17: extension.GetOnuUniInfoResponse_TEN_BASE_T_HDX,
+		18: extension.GetOnuUniInfoResponse_HUNDRED_BASE_T_HDX,
+		19: extension.GetOnuUniInfoResponse_GIGABIT_ETHERNET_HDX,
+	}
+	configInd := meAttributes[configInd].(uint8)
+	singleValResp.Response.GetUniInfo().ConfigInd = configIndMap[configInd]
+	return &singleValResp
+}
+
+func postUniStatusErrResponse(reason extension.GetValueResponse_ErrorReason) *extension.SingleGetValueResponse {
+	return &extension.SingleGetValueResponse{
+		Response: &extension.GetValueResponse{
+			Status:    extension.GetValueResponse_ERROR,
+			ErrReason: reason,
+		},
+	}
+}