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