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