blob: fd98f6b393ea9e3662b7e71da439e2bc9f5e54cd [file] [log] [blame]
Girish Gowdra6afb56a2021-04-27 17:47:57 -07001/*
Joey Armstrong89c812c2024-01-12 19:00:20 -05002 * Copyright 2021-2024 Open Networking Foundation (ONF) and the ONF Contributors
Girish Gowdra6afb56a2021-04-27 17:47:57 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joey Armstrong89c812c2024-01-12 19:00:20 -050017// Package omcitst provides the omci test functionality
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000018package omcitst
Girish Gowdra6afb56a2021-04-27 17:47:57 -070019
20import (
21 "context"
22 "fmt"
khenaidoo7d3c5582021-08-11 18:09:44 -040023 "sync"
24 "time"
25
Girish Gowdra6afb56a2021-04-27 17:47:57 -070026 "github.com/looplab/fsm"
mpagenko836a1fd2021-11-01 16:12:42 +000027 "github.com/opencord/omci-lib-go/v2"
28 "github.com/opencord/omci-lib-go/v2/generated"
29 me "github.com/opencord/omci-lib-go/v2/generated"
khenaidoo7d3c5582021-08-11 18:09:44 -040030 "github.com/opencord/voltha-lib-go/v7/pkg/log"
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000031 cmn "github.com/opencord/voltha-openonu-adapter-go/internal/pkg/common"
khenaidoo7d3c5582021-08-11 18:09:44 -040032 "github.com/opencord/voltha-protos/v5/go/extension"
Girish Gowdra6afb56a2021-04-27 17:47:57 -070033)
34
35const (
36 // events of Self Test FSM
37 selfTestEventTestRequest = "selfTestEventTestRequest"
38 selfTestEventTestResponseSuccess = "selfTestEventTestResponseSuccess"
39 selfTestEventTestResultSuccess = "selfTestEventTestResultSuccess"
40 selfTestEventAbort = "selfTestEventAbort"
41)
42const (
43 // states of Self Test FSM
44 selfTestStNull = "selfTestStNull"
45 selfTestStHandleSelfTestReq = "selfTestStHandleSelfTestReq"
46 selfTestStHandleSelfTestResp = "selfTestStHandleSelfTestResp"
47 selfTestStHandleTestResult = "selfTestStHandleTestResult"
48)
49
50const (
51 //SelfTestResponseWaitTimeout specifies timeout value waiting for self test response. Unit in seconds
52 SelfTestResponseWaitTimeout = 2
53)
54
55// We initiate an fsmCb per Self Test Request
56type fsmCb struct {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000057 fsm *cmn.AdapterFsm
Girish Gowdra6afb56a2021-04-27 17:47:57 -070058 respChan chan extension.SingleGetValueResponse
59 stopOmciChan chan bool
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053060 reqMsg extension.SingleGetValueRequest
Girish Gowdra6afb56a2021-04-27 17:47:57 -070061}
62
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000063// SelfTestControlBlock - TODO: add comment
64type SelfTestControlBlock struct {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000065 pDeviceHandler cmn.IdeviceHandler
66 pDevEntry cmn.IonuDeviceEntry
Girish Gowdra6afb56a2021-04-27 17:47:57 -070067
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053068 selfTestFsmMap map[generated.ClassID]*fsmCb // The fsmCb is indexed by ME Class ID of the Test Action procedure
69 StopSelfTestModule chan bool
70 deviceID string
71 selfTestFsmLock sync.RWMutex
Girish Gowdra6afb56a2021-04-27 17:47:57 -070072
Sridhar Ravindraf1331ad2024-02-15 16:13:37 +053073 SelfTestHandlerLock sync.RWMutex
74 SelfTestHandlerActive bool
Girish Gowdra6afb56a2021-04-27 17:47:57 -070075}
76
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000077// NewSelfTestMsgHandlerCb creates the SelfTestControlBlock
Girish Gowdra6afb56a2021-04-27 17:47:57 -070078// Self Test Handler module supports sending SelfTestRequest and handling of SelfTestResponse/SelfTestResults
79// An ephemeral Self Test FSM is initiated for every Self Test request and multiple Self Tests on different
80// MEs (that support it) can be handled in parallel.
81// At the time of creating this module, only ANI-G self-test is supported.
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000082func NewSelfTestMsgHandlerCb(ctx context.Context, dh cmn.IdeviceHandler, devEntry cmn.IonuDeviceEntry) *SelfTestControlBlock {
83 selfTestCb := SelfTestControlBlock{
84 deviceID: dh.GetDeviceID(),
85 pDeviceHandler: dh,
86 pDevEntry: devEntry,
87 }
Girish Gowdra6afb56a2021-04-27 17:47:57 -070088 selfTestCb.selfTestFsmMap = make(map[generated.ClassID]*fsmCb)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000089 selfTestCb.StopSelfTestModule = make(chan bool)
Girish Gowdra6afb56a2021-04-27 17:47:57 -070090
91 go selfTestCb.waitForStopSelfTestModuleSignal(ctx)
92
93 return &selfTestCb
94}
95
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000096func (selfTestCb *SelfTestControlBlock) initiateNewSelfTestFsm(ctx context.Context, reqMsg extension.SingleGetValueRequest,
97 CommChan chan cmn.Message, classID generated.ClassID, respChan chan extension.SingleGetValueResponse) error {
98 aFsm := cmn.NewAdapterFsm("selfTestFsm", selfTestCb.deviceID, CommChan)
Girish Gowdra6afb56a2021-04-27 17:47:57 -070099
100 if aFsm == nil {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000101 logger.Errorw(ctx, "selfTestFsm cmn.AdapterFsm could not be instantiated!!", log.Fields{
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700102 "device-id": selfTestCb.deviceID})
103 return fmt.Errorf("nil-adapter-fsm")
104 }
105 // Self Test FSM related state machine
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000106 aFsm.PFsm = fsm.NewFSM(
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700107
108 selfTestStNull,
109 fsm.Events{
110 {Name: selfTestEventTestRequest, Src: []string{selfTestStNull}, Dst: selfTestStHandleSelfTestReq},
111 {Name: selfTestEventTestResponseSuccess, Src: []string{selfTestStHandleSelfTestReq}, Dst: selfTestStHandleSelfTestResp},
112 {Name: selfTestEventTestResultSuccess, Src: []string{selfTestStHandleSelfTestResp}, Dst: selfTestStNull},
bseeniva6db14a22024-12-07 19:41:01 +0530113 {Name: selfTestEventAbort, Src: []string{selfTestStHandleSelfTestReq, selfTestStHandleSelfTestResp, selfTestStHandleTestResult,
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000114 selfTestStNull}, Dst: selfTestStNull},
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700115 },
116 fsm.Callbacks{
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000117 "enter_state": func(e *fsm.Event) { aFsm.LogFsmStateChange(ctx, e) },
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700118 "enter_" + selfTestStHandleSelfTestReq: func(e *fsm.Event) { selfTestCb.selfTestFsmHandleSelfTestRequest(ctx, e) },
119 "enter_" + selfTestStHandleSelfTestResp: func(e *fsm.Event) { selfTestCb.selfTestFsmHandleSelfTestResponse(ctx, e) },
120 },
121 )
122 selfTestCb.selfTestFsmLock.Lock()
123 selfTestCb.selfTestFsmMap[classID] = &fsmCb{fsm: aFsm, reqMsg: reqMsg, respChan: respChan, stopOmciChan: make(chan bool)}
124 // Initiate the selfTestEventTestRequest on the FSM. Also pass the additional argument - classID.
125 // This is useful for the the FSM handler function to pull out fsmCb from the selfTestCb.selfTestFsmMap map.
126 selfTestCb.triggerFsmEvent(aFsm, selfTestEventTestRequest, classID)
127 selfTestCb.selfTestFsmLock.Unlock()
128
129 return nil
130}
131
132///// FSM Handlers
133
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000134func (selfTestCb *SelfTestControlBlock) selfTestFsmHandleSelfTestRequest(ctx context.Context, e *fsm.Event) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700135 classID := e.Args[0].(generated.ClassID)
136 selfTestCb.selfTestFsmLock.RLock()
137 pFsmCb, ok := selfTestCb.selfTestFsmMap[classID]
138 selfTestCb.selfTestFsmLock.RUnlock()
139 if !ok {
140 // This case is impossible. Would be curious to see if this happens
141 logger.Fatalw(ctx, "class-id-not-found", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
142 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000143 instKeys := selfTestCb.pDevEntry.GetOnuDB().GetSortedInstKeys(ctx, classID)
Akash Reddy Kankanalabe650282025-07-14 12:19:10 +0530144 if len(instKeys) == 0 {
145 logger.Errorw(ctx, "no instances found for class id", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
146 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
147 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
148 return
149 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000150 // TODO: Choosing the first index from the instance keys. For ANI-G, this is fine as there is only one ANI-G instance.
151 // How do we handle and report self test for multiple instances?
152 if err := selfTestCb.pDevEntry.GetDevOmciCC().SendSelfTestReq(ctx, classID, instKeys[0], selfTestCb.pDeviceHandler.GetOmciTimeout(),
153 false, pFsmCb.fsm.CommChan); err != nil {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700154 logger.Errorw(ctx, "error sending self test request", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
155 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530156 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700157 return
158 }
159
160 go selfTestCb.handleOmciResponse(ctx, classID)
161}
162
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000163func (selfTestCb *SelfTestControlBlock) selfTestFsmHandleSelfTestResponse(ctx context.Context, e *fsm.Event) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700164 classID := e.Args[0].(generated.ClassID)
165 // Pass the test result processing to another routine
166 go selfTestCb.handleOmciResponse(ctx, classID)
167
168}
169
170///// Utility functions
171
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000172func (selfTestCb *SelfTestControlBlock) getMeClassID(ctx context.Context, reqMsg extension.SingleGetValueRequest) (generated.ClassID, error) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700173 switch reqMsg.GetRequest().GetRequest().(type) {
174 case *extension.GetValueRequest_OnuOpticalInfo:
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000175 return me.AniGClassID, nil
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700176 default:
177 logger.Warnw(ctx, "unsupported me class id for self test", log.Fields{"device-id": selfTestCb.deviceID})
178 return 0, fmt.Errorf("unsupported me class id for self test %v", selfTestCb.deviceID)
179 }
180}
181
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000182func (selfTestCb *SelfTestControlBlock) triggerFsmEvent(pSelfTestFsm *cmn.AdapterFsm, event string, args ...generated.ClassID) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700183 go func() {
184 if len(args) > 0 {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000185 _ = pSelfTestFsm.PFsm.Event(event, args[0])
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700186 } else {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000187 _ = pSelfTestFsm.PFsm.Event(event)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700188 }
189 }()
190}
191
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530192//nolint:unparam
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000193func (selfTestCb *SelfTestControlBlock) submitFailureGetValueResponse(ctx context.Context, respChan chan extension.SingleGetValueResponse,
bseeniva6db14a22024-12-07 19:41:01 +0530194 errorCode extension.GetValueResponse_ErrorReason, statusCode extension.GetValueResponse_Status, reqMsg extension.SingleGetValueRequest) {
195 meClassID, err := selfTestCb.getMeClassID(ctx, reqMsg)
196 if err != nil {
197 return
198 }
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700199 singleValResp := extension.SingleGetValueResponse{
200 Response: &extension.GetValueResponse{
201 Status: statusCode,
202 ErrReason: errorCode,
203 },
204 }
205 logger.Infow(ctx, "OMCI test response failure - pushing failure response", log.Fields{"device-id": selfTestCb.deviceID})
bseeniva6db14a22024-12-07 19:41:01 +0530206 // Clear the fsmCb from the map
207 delete(selfTestCb.selfTestFsmMap, meClassID)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700208 respChan <- singleValResp
209 logger.Infow(ctx, "OMCI test response failure - pushing failure response complete", log.Fields{"device-id": selfTestCb.deviceID})
210}
211
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000212func (selfTestCb *SelfTestControlBlock) handleOmciMessage(ctx context.Context, msg cmn.OmciMessage, cb *fsmCb, classID generated.ClassID) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700213 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": selfTestCb.deviceID, "msgType": msg.OmciMsg.MessageType, "msg": msg})
214 switch msg.OmciMsg.MessageType {
215 case omci.TestResponseType:
216 selfTestCb.handleOmciTestResponse(ctx, msg, cb, classID)
217 case omci.TestResultType:
218 selfTestCb.handleOmciTestResult(ctx, msg, cb, classID)
219 default:
220 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
221 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530222 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700223 }
224}
225
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000226func (selfTestCb *SelfTestControlBlock) handleOmciTestResponse(ctx context.Context, msg cmn.OmciMessage, cb *fsmCb, classID generated.ClassID) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700227 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeTestResponse)
228 if msgLayer == nil {
229 logger.Errorw(ctx, "omci Msg layer nil self test response", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000230 selfTestCb.pDevEntry.GetDevOmciCC().ReleaseTid(ctx, msg.OmciMsg.TransactionID)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700231 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530232 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700233 return
234 }
235 msgObj, msgOk := msgLayer.(*omci.TestResponse)
236 if !msgOk {
237 logger.Errorw(ctx, "omci Msg layer could not be detected for self test response", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000238 selfTestCb.pDevEntry.GetDevOmciCC().ReleaseTid(ctx, msg.OmciMsg.TransactionID)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700239 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530240 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700241 return
242 }
243 logger.Debugw(ctx, "OMCI test response Data", log.Fields{"device-id": selfTestCb.deviceID, "data-fields": msgObj})
244 if msgObj.Result == generated.Success && msgObj.EntityClass == classID {
245 logger.Infow(ctx, "OMCI test response success", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
246 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventTestResponseSuccess, classID)
247 return
248 }
249
250 logger.Infow(ctx, "OMCI test response failure", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000251 selfTestCb.pDevEntry.GetDevOmciCC().ReleaseTid(ctx, msg.OmciMsg.TransactionID)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700252 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530253 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700254}
255
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000256func (selfTestCb *SelfTestControlBlock) handleOmciTestResult(ctx context.Context, msg cmn.OmciMessage, cb *fsmCb, classID generated.ClassID) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700257 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeTestResult)
258 if msgLayer == nil {
259 logger.Errorw(ctx, "omci Msg layer nil self test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
260 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530261 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700262 return
263 }
264 var msgObj *omci.OpticalLineSupervisionTestResult
265 var msgOk bool
266 switch classID {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000267 case me.AniGClassID:
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700268 msgObj, msgOk = msgLayer.(*omci.OpticalLineSupervisionTestResult)
269 default:
270 // We should not really land here
271 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530272 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700273 return
274 }
275 if !msgOk {
276 logger.Errorw(ctx, "omci Msg layer could not be detected for self test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
277 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530278 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, cb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700279 return
280 }
281 logger.Debugw(ctx, "raw omci values of ani-g test result",
282 log.Fields{"device-id": selfTestCb.deviceID,
283 "power-feed-voltage": msgObj.PowerFeedVoltage,
284 "rx-power": msgObj.ReceivedOpticalPower,
285 "tx-power": msgObj.MeanOpticalLaunch,
286 "laser-bias-current": msgObj.LaserBiasCurrent,
287 "temperature": msgObj.Temperature})
288 singleValResp := extension.SingleGetValueResponse{
289 Response: &extension.GetValueResponse{
290 Status: extension.GetValueResponse_OK,
291 Response: &extension.GetValueResponse_OnuOpticalInfo{
292 OnuOpticalInfo: &extension.GetOnuPonOpticalInfoResponse{
293 // OMCI representation is Volts, 2s compliment, 20mV resolution
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000294 PowerFeedVoltage: float32(cmn.TwosComplementToSignedInt16(msgObj.PowerFeedVoltage)) * 0.02,
Girish Gowdra444522f2021-05-12 14:32:24 -0700295 // OMCI representation is Decibel-microwatts, 2s compliment, 0.002dB resolution.
296 // Subtract 30 to convert the unit from dBu to dBm (as expected by proto interface)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000297 ReceivedOpticalPower: float32(cmn.TwosComplementToSignedInt16(msgObj.ReceivedOpticalPower))*0.002 - 30,
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700298 // OMCI representation is Decibel-microwatts, 2s compliment, 0.002dB resolution
Girish Gowdra444522f2021-05-12 14:32:24 -0700299 // Subtract 30 to convert the unit from dBu to dBm (as expected by proto interface)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000300 MeanOpticalLaunchPower: float32(cmn.TwosComplementToSignedInt16(msgObj.MeanOpticalLaunch))*0.002 - 30,
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700301 // OMCI representation is unsigned int, 2uA resolution
302 // units of gRPC interface is mA.
303 LaserBiasCurrent: float32(msgObj.LaserBiasCurrent) * 0.000002 * 1000, // multiply by 1000 to get units in mA
304 // OMCI representation is 2s complement, 1/256 degree Celsius resolution
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000305 Temperature: float32(cmn.TwosComplementToSignedInt16(msgObj.Temperature)) / 256.0,
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700306 },
307 },
308 },
309 }
310 logger.Debugw(ctx, "ani-g test result after type/value conversion",
311 log.Fields{"device-id": selfTestCb.deviceID,
312 "power-feed-voltage": singleValResp.Response.GetOnuOpticalInfo().PowerFeedVoltage,
313 "rx-power": singleValResp.Response.GetOnuOpticalInfo().ReceivedOpticalPower,
314 "tx-power": singleValResp.Response.GetOnuOpticalInfo().MeanOpticalLaunchPower,
315 "laser-bias-current": singleValResp.Response.GetOnuOpticalInfo().LaserBiasCurrent,
316 "temperature": singleValResp.Response.GetOnuOpticalInfo().Temperature})
317 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventTestResultSuccess)
318 logger.Infow(ctx, "OMCI test result success - pushing results", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
319 cb.respChan <- singleValResp
320 selfTestCb.selfTestRequestComplete(ctx, cb.reqMsg)
321 logger.Infow(ctx, "OMCI test result success - pushing results complete", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
322}
323
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000324func (selfTestCb *SelfTestControlBlock) handleOmciResponse(ctx context.Context, classID generated.ClassID) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700325 selfTestCb.selfTestFsmLock.RLock()
326 pFsmCb, ok := selfTestCb.selfTestFsmMap[classID]
327 selfTestCb.selfTestFsmLock.RUnlock()
328 if !ok {
329 logger.Errorw(ctx, "fsb control block unavailable", log.Fields{"device-id": selfTestCb.deviceID, "class-id": classID})
330 return
331 }
332 select {
333 case <-pFsmCb.stopOmciChan:
334 logger.Infow(ctx, "omci processing stopped", log.Fields{"device-id": selfTestCb.deviceID, "class-id": classID})
335 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530336 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_REASON_UNDEFINED, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000337 case message, ok := <-pFsmCb.fsm.CommChan:
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700338 if !ok {
339 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": selfTestCb.deviceID})
340 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530341 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700342 }
343 logger.Debugw(ctx, "Received message on self test result channel", log.Fields{"device-id": selfTestCb.deviceID})
344
345 switch message.Type {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000346 case cmn.OMCI:
347 msg, _ := message.Data.(cmn.OmciMessage)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700348 selfTestCb.handleOmciMessage(ctx, msg, pFsmCb, classID)
349 default:
350 logger.Errorw(ctx, "Unknown message type received", log.Fields{"device-id": selfTestCb.deviceID, "message.Type": message.Type})
bseeniva6db14a22024-12-07 19:41:01 +0530351 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700352 }
353 case <-time.After(time.Duration(SelfTestResponseWaitTimeout) * time.Second):
354 logger.Errorw(ctx, "timeout waiting for test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
355 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530356 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_TIMEOUT, extension.GetValueResponse_ERROR, pFsmCb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700357 }
358}
359
360// selfTestRequestComplete removes the fsmCb from the local cache if found
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000361func (selfTestCb *SelfTestControlBlock) selfTestRequestComplete(ctx context.Context, reqMsg extension.SingleGetValueRequest) {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700362 meClassID, err := selfTestCb.getMeClassID(ctx, reqMsg)
363 if err != nil {
364 return
365 }
366 logger.Infow(ctx, "self test req handling complete", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": meClassID})
367 // Clear the fsmCb from the map
368 delete(selfTestCb.selfTestFsmMap, meClassID)
369}
370
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000371func (selfTestCb *SelfTestControlBlock) waitForStopSelfTestModuleSignal(ctx context.Context) {
Girish Gowdra10123c02021-08-30 11:52:06 -0700372 selfTestCb.SetSelfTestHandlerIsRunning(true)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000373 <-selfTestCb.StopSelfTestModule // block on stop signal
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700374
375 logger.Infow(ctx, "received stop signal - clean up start", log.Fields{"device-id": selfTestCb.deviceID})
376 selfTestCb.selfTestFsmLock.Lock()
377 for classID, fsmCb := range selfTestCb.selfTestFsmMap {
378 select {
379 case fsmCb.stopOmciChan <- true: // stop omci processing routine if one was active. It eventually aborts the fsm
380 logger.Debugw(ctx, "stopped omci processing", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": classID})
381 default:
382 selfTestCb.triggerFsmEvent(fsmCb.fsm, selfTestEventAbort)
bseeniva6db14a22024-12-07 19:41:01 +0530383 selfTestCb.submitFailureGetValueResponse(ctx, fsmCb.respChan, extension.GetValueResponse_REASON_UNDEFINED, extension.GetValueResponse_ERROR, fsmCb.reqMsg)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700384 }
385 }
386 selfTestCb.selfTestFsmMap = make(map[generated.ClassID]*fsmCb) // reset map
387 selfTestCb.selfTestFsmLock.Unlock()
388 logger.Infow(ctx, "received stop signal - clean up end", log.Fields{"device-id": selfTestCb.deviceID})
389}
390
391//// Exported functions
392
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000393// SetSelfTestHandlerIsRunning sets the value to selfTestCb.selfTestHandlerActive
394func (selfTestCb *SelfTestControlBlock) SetSelfTestHandlerIsRunning(active bool) {
Sridhar Ravindraf1331ad2024-02-15 16:13:37 +0530395 selfTestCb.SelfTestHandlerLock.Lock()
396 defer selfTestCb.SelfTestHandlerLock.Unlock()
397 selfTestCb.SelfTestHandlerActive = active
Girish Gowdra10123c02021-08-30 11:52:06 -0700398}
399
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000400// GetSelfTestHandlerIsRunning gets selfTestCb.selfTestHandlerActive
401func (selfTestCb *SelfTestControlBlock) GetSelfTestHandlerIsRunning() bool {
Sridhar Ravindraf1331ad2024-02-15 16:13:37 +0530402 selfTestCb.SelfTestHandlerLock.RLock()
403 defer selfTestCb.SelfTestHandlerLock.RUnlock()
404 return selfTestCb.SelfTestHandlerActive
Girish Gowdra10123c02021-08-30 11:52:06 -0700405}
406
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000407// SelfTestRequestStart initiate Test Request handling procedure. The results are asynchronously conveyed on the respChan.
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700408// If the return from selfTestRequest is NOT nil, the caller shall not wait for async response.
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000409func (selfTestCb *SelfTestControlBlock) SelfTestRequestStart(ctx context.Context, reqMsg extension.SingleGetValueRequest,
410 CommChan chan cmn.Message, respChan chan extension.SingleGetValueResponse) error {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700411 meClassID, err := selfTestCb.getMeClassID(ctx, reqMsg)
412 if err != nil {
413 return err
414 }
415 if _, ok := selfTestCb.selfTestFsmMap[meClassID]; ok {
416 logger.Errorw(ctx, "self test already in progress for class id", log.Fields{"device-id": selfTestCb.deviceID, "class-id": meClassID})
417 return fmt.Errorf("self-test-already-in-progress-for-class-id-%v-device-id-%v", meClassID, selfTestCb.deviceID)
418 }
419 logger.Infow(ctx, "self test request initiated", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": meClassID})
420 // indicates only if the FSM was initiated correctly. Response is asynchronous on respChan.
421 // If the return from here is NOT nil, the caller shall not wait for async response.
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000422 return selfTestCb.initiateNewSelfTestFsm(ctx, reqMsg, CommChan, meClassID, respChan)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700423}
Holger Hildebrandte7cc6092022-02-01 11:37:03 +0000424
425// PrepareForGarbageCollection - remove references to prepare for garbage collection
426func (selfTestCb *SelfTestControlBlock) PrepareForGarbageCollection(ctx context.Context, aDeviceID string) {
427 logger.Debugw(ctx, "prepare for garbage collection", log.Fields{"device-id": aDeviceID})
428 selfTestCb.pDeviceHandler = nil
429 selfTestCb.pDevEntry = nil
430}