blob: ce82db8858eb152c7270605ec572ccaea85836b7 [file] [log] [blame]
Girish Gowdra6afb56a2021-04-27 17:47:57 -07001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
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
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
22 "fmt"
23 "github.com/looplab/fsm"
24 "github.com/opencord/omci-lib-go"
25 "github.com/opencord/omci-lib-go/generated"
Girish Gowdra50e56422021-06-01 16:46:04 -070026 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Girish Gowdra6afb56a2021-04-27 17:47:57 -070027 "github.com/opencord/voltha-protos/v4/go/extension"
28 "sync"
29 "time"
30)
31
32const (
33 // events of Self Test FSM
34 selfTestEventTestRequest = "selfTestEventTestRequest"
35 selfTestEventTestResponseSuccess = "selfTestEventTestResponseSuccess"
36 selfTestEventTestResultSuccess = "selfTestEventTestResultSuccess"
37 selfTestEventAbort = "selfTestEventAbort"
38)
39const (
40 // states of Self Test FSM
41 selfTestStNull = "selfTestStNull"
42 selfTestStHandleSelfTestReq = "selfTestStHandleSelfTestReq"
43 selfTestStHandleSelfTestResp = "selfTestStHandleSelfTestResp"
44 selfTestStHandleTestResult = "selfTestStHandleTestResult"
45)
46
47const (
48 //SelfTestResponseWaitTimeout specifies timeout value waiting for self test response. Unit in seconds
49 SelfTestResponseWaitTimeout = 2
50)
51
52// We initiate an fsmCb per Self Test Request
53type fsmCb struct {
54 fsm *AdapterFsm
55 reqMsg extension.SingleGetValueRequest
56 respChan chan extension.SingleGetValueResponse
57 stopOmciChan chan bool
58}
59
60type selfTestControlBlock struct {
61 pDeviceHandler *deviceHandler
62 deviceID string
63
64 selfTestFsmMap map[generated.ClassID]*fsmCb // The fsmCb is indexed by ME Class ID of the Test Action procedure
65 selfTestFsmLock sync.RWMutex
66
Girish Gowdra10123c02021-08-30 11:52:06 -070067 selfTestHandlerLock sync.RWMutex
68 selfTestHandlerActive bool
69 stopSelfTestModule chan bool
Girish Gowdra6afb56a2021-04-27 17:47:57 -070070}
71
72// newSelfTestMsgHandlerCb creates the selfTestControlBlock
73// Self Test Handler module supports sending SelfTestRequest and handling of SelfTestResponse/SelfTestResults
74// An ephemeral Self Test FSM is initiated for every Self Test request and multiple Self Tests on different
75// MEs (that support it) can be handled in parallel.
76// At the time of creating this module, only ANI-G self-test is supported.
77func newSelfTestMsgHandlerCb(ctx context.Context, dh *deviceHandler) *selfTestControlBlock {
78 selfTestCb := selfTestControlBlock{pDeviceHandler: dh}
79 selfTestCb.selfTestFsmMap = make(map[generated.ClassID]*fsmCb)
80 selfTestCb.deviceID = selfTestCb.pDeviceHandler.deviceID
81 selfTestCb.stopSelfTestModule = make(chan bool)
82
83 go selfTestCb.waitForStopSelfTestModuleSignal(ctx)
84
85 return &selfTestCb
86}
87
88func (selfTestCb *selfTestControlBlock) initiateNewSelfTestFsm(ctx context.Context, reqMsg extension.SingleGetValueRequest, commChan chan Message, classID generated.ClassID, respChan chan extension.SingleGetValueResponse) error {
89 aFsm := NewAdapterFsm("selfTestFsm", selfTestCb.deviceID, commChan)
90
91 if aFsm == nil {
92 logger.Errorw(ctx, "selfTestFsm AdapterFsm could not be instantiated!!", log.Fields{
93 "device-id": selfTestCb.deviceID})
94 return fmt.Errorf("nil-adapter-fsm")
95 }
96 // Self Test FSM related state machine
97 aFsm.pFsm = fsm.NewFSM(
98
99 selfTestStNull,
100 fsm.Events{
101 {Name: selfTestEventTestRequest, Src: []string{selfTestStNull}, Dst: selfTestStHandleSelfTestReq},
102 {Name: selfTestEventTestResponseSuccess, Src: []string{selfTestStHandleSelfTestReq}, Dst: selfTestStHandleSelfTestResp},
103 {Name: selfTestEventTestResultSuccess, Src: []string{selfTestStHandleSelfTestResp}, Dst: selfTestStNull},
104 {Name: selfTestEventAbort, Src: []string{selfTestStHandleSelfTestReq, selfTestStHandleSelfTestReq, selfTestStHandleTestResult, selfTestStNull}, Dst: selfTestStNull},
105 },
106 fsm.Callbacks{
107 "enter_state": func(e *fsm.Event) { aFsm.logFsmStateChange(ctx, e) },
108 "enter_" + selfTestStHandleSelfTestReq: func(e *fsm.Event) { selfTestCb.selfTestFsmHandleSelfTestRequest(ctx, e) },
109 "enter_" + selfTestStHandleSelfTestResp: func(e *fsm.Event) { selfTestCb.selfTestFsmHandleSelfTestResponse(ctx, e) },
110 },
111 )
112 selfTestCb.selfTestFsmLock.Lock()
113 selfTestCb.selfTestFsmMap[classID] = &fsmCb{fsm: aFsm, reqMsg: reqMsg, respChan: respChan, stopOmciChan: make(chan bool)}
114 // Initiate the selfTestEventTestRequest on the FSM. Also pass the additional argument - classID.
115 // This is useful for the the FSM handler function to pull out fsmCb from the selfTestCb.selfTestFsmMap map.
116 selfTestCb.triggerFsmEvent(aFsm, selfTestEventTestRequest, classID)
117 selfTestCb.selfTestFsmLock.Unlock()
118
119 return nil
120}
121
122///// FSM Handlers
123
124func (selfTestCb *selfTestControlBlock) selfTestFsmHandleSelfTestRequest(ctx context.Context, e *fsm.Event) {
125 classID := e.Args[0].(generated.ClassID)
126 selfTestCb.selfTestFsmLock.RLock()
127 pFsmCb, ok := selfTestCb.selfTestFsmMap[classID]
128 selfTestCb.selfTestFsmLock.RUnlock()
129 if !ok {
130 // This case is impossible. Would be curious to see if this happens
131 logger.Fatalw(ctx, "class-id-not-found", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
132 }
133 instKeys := selfTestCb.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, classID)
134
135 // TODO: Choosing the first index from the instance keys. For ANI-G, this is fine as there is only one ANI-G instance. How do we handle and report self test for multiple instances?
136 if err := selfTestCb.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSelfTestReq(ctx, classID, instKeys[0], selfTestCb.pDeviceHandler.pOpenOnuAc.omciTimeout, false, pFsmCb.fsm.commChan); err != nil {
137 logger.Errorw(ctx, "error sending self test request", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
138 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
139 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
140 return
141 }
142
143 go selfTestCb.handleOmciResponse(ctx, classID)
144}
145
146func (selfTestCb *selfTestControlBlock) selfTestFsmHandleSelfTestResponse(ctx context.Context, e *fsm.Event) {
147 classID := e.Args[0].(generated.ClassID)
148 // Pass the test result processing to another routine
149 go selfTestCb.handleOmciResponse(ctx, classID)
150
151}
152
153///// Utility functions
154
155func (selfTestCb *selfTestControlBlock) getMeClassID(ctx context.Context, reqMsg extension.SingleGetValueRequest) (generated.ClassID, error) {
156 switch reqMsg.GetRequest().GetRequest().(type) {
157 case *extension.GetValueRequest_OnuOpticalInfo:
158 return aniGClassID, nil
159 default:
160 logger.Warnw(ctx, "unsupported me class id for self test", log.Fields{"device-id": selfTestCb.deviceID})
161 return 0, fmt.Errorf("unsupported me class id for self test %v", selfTestCb.deviceID)
162 }
163}
164
165func (selfTestCb *selfTestControlBlock) triggerFsmEvent(pSelfTestFsm *AdapterFsm, event string, args ...generated.ClassID) {
166 go func() {
167 if len(args) > 0 {
168 _ = pSelfTestFsm.pFsm.Event(event, args[0])
169 } else {
170 _ = pSelfTestFsm.pFsm.Event(event)
171 }
172 }()
173}
174
175func (selfTestCb *selfTestControlBlock) submitFailureGetValueResponse(ctx context.Context, respChan chan extension.SingleGetValueResponse, errorCode extension.GetValueResponse_ErrorReason, statusCode extension.GetValueResponse_Status) {
176 singleValResp := extension.SingleGetValueResponse{
177 Response: &extension.GetValueResponse{
178 Status: statusCode,
179 ErrReason: errorCode,
180 },
181 }
182 logger.Infow(ctx, "OMCI test response failure - pushing failure response", log.Fields{"device-id": selfTestCb.deviceID})
183 respChan <- singleValResp
184 logger.Infow(ctx, "OMCI test response failure - pushing failure response complete", log.Fields{"device-id": selfTestCb.deviceID})
185}
186
187func (selfTestCb *selfTestControlBlock) handleOmciMessage(ctx context.Context, msg OmciMessage, cb *fsmCb, classID generated.ClassID) {
188 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": selfTestCb.deviceID, "msgType": msg.OmciMsg.MessageType, "msg": msg})
189 switch msg.OmciMsg.MessageType {
190 case omci.TestResponseType:
191 selfTestCb.handleOmciTestResponse(ctx, msg, cb, classID)
192 case omci.TestResultType:
193 selfTestCb.handleOmciTestResult(ctx, msg, cb, classID)
194 default:
195 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
196 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
197 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR)
198 }
199}
200
201func (selfTestCb *selfTestControlBlock) handleOmciTestResponse(ctx context.Context, msg OmciMessage, cb *fsmCb, classID generated.ClassID) {
202 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeTestResponse)
203 if msgLayer == nil {
204 logger.Errorw(ctx, "omci Msg layer nil self test response", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
205 selfTestCb.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.ReleaseTid(ctx, msg.OmciMsg.TransactionID)
206 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
207 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
208 return
209 }
210 msgObj, msgOk := msgLayer.(*omci.TestResponse)
211 if !msgOk {
212 logger.Errorw(ctx, "omci Msg layer could not be detected for self test response", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
213 selfTestCb.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.ReleaseTid(ctx, msg.OmciMsg.TransactionID)
214 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
215 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
216 return
217 }
218 logger.Debugw(ctx, "OMCI test response Data", log.Fields{"device-id": selfTestCb.deviceID, "data-fields": msgObj})
219 if msgObj.Result == generated.Success && msgObj.EntityClass == classID {
220 logger.Infow(ctx, "OMCI test response success", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
221 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventTestResponseSuccess, classID)
222 return
223 }
224
225 logger.Infow(ctx, "OMCI test response failure", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
226 selfTestCb.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.ReleaseTid(ctx, msg.OmciMsg.TransactionID)
227 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
228 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR)
229}
230
231func (selfTestCb *selfTestControlBlock) handleOmciTestResult(ctx context.Context, msg OmciMessage, cb *fsmCb, classID generated.ClassID) {
232 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeTestResult)
233 if msgLayer == nil {
234 logger.Errorw(ctx, "omci Msg layer nil self test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
235 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
236 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
237 return
238 }
239 var msgObj *omci.OpticalLineSupervisionTestResult
240 var msgOk bool
241 switch classID {
242 case aniGClassID:
243 msgObj, msgOk = msgLayer.(*omci.OpticalLineSupervisionTestResult)
244 default:
245 // We should not really land here
246 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
247 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
248 return
249 }
250 if !msgOk {
251 logger.Errorw(ctx, "omci Msg layer could not be detected for self test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
252 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventAbort)
253 selfTestCb.submitFailureGetValueResponse(ctx, cb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
254 return
255 }
256 logger.Debugw(ctx, "raw omci values of ani-g test result",
257 log.Fields{"device-id": selfTestCb.deviceID,
258 "power-feed-voltage": msgObj.PowerFeedVoltage,
259 "rx-power": msgObj.ReceivedOpticalPower,
260 "tx-power": msgObj.MeanOpticalLaunch,
261 "laser-bias-current": msgObj.LaserBiasCurrent,
262 "temperature": msgObj.Temperature})
263 singleValResp := extension.SingleGetValueResponse{
264 Response: &extension.GetValueResponse{
265 Status: extension.GetValueResponse_OK,
266 Response: &extension.GetValueResponse_OnuOpticalInfo{
267 OnuOpticalInfo: &extension.GetOnuPonOpticalInfoResponse{
268 // OMCI representation is Volts, 2s compliment, 20mV resolution
269 PowerFeedVoltage: float32(TwosComplementToSignedInt16(msgObj.PowerFeedVoltage)) * 0.02,
Girish Gowdra444522f2021-05-12 14:32:24 -0700270 // OMCI representation is Decibel-microwatts, 2s compliment, 0.002dB resolution.
271 // Subtract 30 to convert the unit from dBu to dBm (as expected by proto interface)
272 ReceivedOpticalPower: float32(TwosComplementToSignedInt16(msgObj.ReceivedOpticalPower))*0.002 - 30,
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700273 // OMCI representation is Decibel-microwatts, 2s compliment, 0.002dB resolution
Girish Gowdra444522f2021-05-12 14:32:24 -0700274 // Subtract 30 to convert the unit from dBu to dBm (as expected by proto interface)
275 MeanOpticalLaunchPower: float32(TwosComplementToSignedInt16(msgObj.MeanOpticalLaunch))*0.002 - 30,
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700276 // OMCI representation is unsigned int, 2uA resolution
277 // units of gRPC interface is mA.
278 LaserBiasCurrent: float32(msgObj.LaserBiasCurrent) * 0.000002 * 1000, // multiply by 1000 to get units in mA
279 // OMCI representation is 2s complement, 1/256 degree Celsius resolution
280 Temperature: float32(TwosComplementToSignedInt16(msgObj.Temperature)) / 256.0,
281 },
282 },
283 },
284 }
285 logger.Debugw(ctx, "ani-g test result after type/value conversion",
286 log.Fields{"device-id": selfTestCb.deviceID,
287 "power-feed-voltage": singleValResp.Response.GetOnuOpticalInfo().PowerFeedVoltage,
288 "rx-power": singleValResp.Response.GetOnuOpticalInfo().ReceivedOpticalPower,
289 "tx-power": singleValResp.Response.GetOnuOpticalInfo().MeanOpticalLaunchPower,
290 "laser-bias-current": singleValResp.Response.GetOnuOpticalInfo().LaserBiasCurrent,
291 "temperature": singleValResp.Response.GetOnuOpticalInfo().Temperature})
292 selfTestCb.triggerFsmEvent(cb.fsm, selfTestEventTestResultSuccess)
293 logger.Infow(ctx, "OMCI test result success - pushing results", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
294 cb.respChan <- singleValResp
295 selfTestCb.selfTestRequestComplete(ctx, cb.reqMsg)
296 logger.Infow(ctx, "OMCI test result success - pushing results complete", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
297}
298
299func (selfTestCb *selfTestControlBlock) handleOmciResponse(ctx context.Context, classID generated.ClassID) {
300 selfTestCb.selfTestFsmLock.RLock()
301 pFsmCb, ok := selfTestCb.selfTestFsmMap[classID]
302 selfTestCb.selfTestFsmLock.RUnlock()
303 if !ok {
304 logger.Errorw(ctx, "fsb control block unavailable", log.Fields{"device-id": selfTestCb.deviceID, "class-id": classID})
305 return
306 }
307 select {
308 case <-pFsmCb.stopOmciChan:
309 logger.Infow(ctx, "omci processing stopped", log.Fields{"device-id": selfTestCb.deviceID, "class-id": classID})
310 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
311 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_REASON_UNDEFINED, extension.GetValueResponse_ERROR)
312 case message, ok := <-pFsmCb.fsm.commChan:
313 if !ok {
314 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": selfTestCb.deviceID})
315 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
316 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_INTERNAL_ERROR, extension.GetValueResponse_ERROR)
317 }
318 logger.Debugw(ctx, "Received message on self test result channel", log.Fields{"device-id": selfTestCb.deviceID})
319
320 switch message.Type {
321 case OMCI:
322 msg, _ := message.Data.(OmciMessage)
323 selfTestCb.handleOmciMessage(ctx, msg, pFsmCb, classID)
324 default:
325 logger.Errorw(ctx, "Unknown message type received", log.Fields{"device-id": selfTestCb.deviceID, "message.Type": message.Type})
326 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_UNSUPPORTED, extension.GetValueResponse_ERROR)
327 }
328 case <-time.After(time.Duration(SelfTestResponseWaitTimeout) * time.Second):
329 logger.Errorw(ctx, "timeout waiting for test result", log.Fields{"device-id": selfTestCb.deviceID, "classID": classID})
330 selfTestCb.triggerFsmEvent(pFsmCb.fsm, selfTestEventAbort)
331 selfTestCb.submitFailureGetValueResponse(ctx, pFsmCb.respChan, extension.GetValueResponse_TIMEOUT, extension.GetValueResponse_ERROR)
332 }
333}
334
335// selfTestRequestComplete removes the fsmCb from the local cache if found
336func (selfTestCb *selfTestControlBlock) selfTestRequestComplete(ctx context.Context, reqMsg extension.SingleGetValueRequest) {
337 meClassID, err := selfTestCb.getMeClassID(ctx, reqMsg)
338 if err != nil {
339 return
340 }
341 logger.Infow(ctx, "self test req handling complete", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": meClassID})
342 // Clear the fsmCb from the map
343 delete(selfTestCb.selfTestFsmMap, meClassID)
344}
345
346func (selfTestCb *selfTestControlBlock) waitForStopSelfTestModuleSignal(ctx context.Context) {
Girish Gowdra10123c02021-08-30 11:52:06 -0700347 selfTestCb.SetSelfTestHandlerIsRunning(true)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700348 <-selfTestCb.stopSelfTestModule // block on stop signal
Girish Gowdra10123c02021-08-30 11:52:06 -0700349 selfTestCb.SetSelfTestHandlerIsRunning(false)
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700350
351 logger.Infow(ctx, "received stop signal - clean up start", log.Fields{"device-id": selfTestCb.deviceID})
352 selfTestCb.selfTestFsmLock.Lock()
353 for classID, fsmCb := range selfTestCb.selfTestFsmMap {
354 select {
355 case fsmCb.stopOmciChan <- true: // stop omci processing routine if one was active. It eventually aborts the fsm
356 logger.Debugw(ctx, "stopped omci processing", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": classID})
357 default:
358 selfTestCb.triggerFsmEvent(fsmCb.fsm, selfTestEventAbort)
359 selfTestCb.submitFailureGetValueResponse(ctx, fsmCb.respChan, extension.GetValueResponse_REASON_UNDEFINED, extension.GetValueResponse_ERROR)
360 }
361 }
362 selfTestCb.selfTestFsmMap = make(map[generated.ClassID]*fsmCb) // reset map
363 selfTestCb.selfTestFsmLock.Unlock()
364 logger.Infow(ctx, "received stop signal - clean up end", log.Fields{"device-id": selfTestCb.deviceID})
365}
366
367//// Exported functions
368
Girish Gowdra10123c02021-08-30 11:52:06 -0700369// SetSelfTestHandlerActive sets the value to selfTestCb.selfTestHandlerActive
370func (selfTestCb *selfTestControlBlock) SetSelfTestHandlerIsRunning(active bool) {
371 selfTestCb.selfTestHandlerLock.Lock()
372 defer selfTestCb.selfTestHandlerLock.Unlock()
373 selfTestCb.selfTestHandlerActive = active
374}
375
376// GetSelfTestHandlerActive gets selfTestCb.selfTestHandlerActive
377func (selfTestCb *selfTestControlBlock) GetSelfTestHandlerIsRunning() bool {
378 selfTestCb.selfTestHandlerLock.RLock()
379 defer selfTestCb.selfTestHandlerLock.RUnlock()
380 return selfTestCb.selfTestHandlerActive
381}
382
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700383// selfTestRequest initiate Test Request handling procedure. The results are asynchronously conveyed on the respChan.
384// If the return from selfTestRequest is NOT nil, the caller shall not wait for async response.
385func (selfTestCb *selfTestControlBlock) SelfTestRequestStart(ctx context.Context, reqMsg extension.SingleGetValueRequest, commChan chan Message, respChan chan extension.SingleGetValueResponse) error {
386 meClassID, err := selfTestCb.getMeClassID(ctx, reqMsg)
387 if err != nil {
388 return err
389 }
390 if _, ok := selfTestCb.selfTestFsmMap[meClassID]; ok {
391 logger.Errorw(ctx, "self test already in progress for class id", log.Fields{"device-id": selfTestCb.deviceID, "class-id": meClassID})
392 return fmt.Errorf("self-test-already-in-progress-for-class-id-%v-device-id-%v", meClassID, selfTestCb.deviceID)
393 }
394 logger.Infow(ctx, "self test request initiated", log.Fields{"device-id": selfTestCb.deviceID, "meClassID": meClassID})
395 // indicates only if the FSM was initiated correctly. Response is asynchronous on respChan.
396 // If the return from here is NOT nil, the caller shall not wait for async response.
397 return selfTestCb.initiateNewSelfTestFsm(ctx, reqMsg, commChan, meClassID, respChan)
398}