blob: 2fe4be30f98c2bd92341b5d798717eede4c5b8d0 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_LGenBaseDemo_ResponderFunctions
//
// Purpose:
// This module contains the functions of the Responder component of the LGenBase demo
//
// Module Parameters:
// -
//
// Module depends on:
//
// Current Owner:
// ELSZSKU
//
// Last Review Date:
// 20 - -
//
// Detailed Comments:
//
///////////////////////////////////////////////////////////
module EPTF_LGenBaseDemo_ResponderFunctions
{
import from EPTF_CLL_LGenBase_EventHandlingFunctions all;
import from EPTF_CLL_Variable_Definitions all;
import from EPTF_CLL_Variable_Functions all;
import from EPTF_CLL_Common_Definitions all;
import from EPTF_CLL_LGenBase_Definitions all;
import from EPTF_LGenBaseDemo_TransportDefinitions all
import from EPTF_LGenBaseDemo_TransportFunctions all
import from EPTF_CLL_Base_Functions all;
import from EPTF_CLL_LGenBase_ConfigFunctions all;
import from EPTF_CLL_LGenBase_Functions all;
import from EPTF_CLL_LGenBase_ConfigDefinitions all;
import from EPTF_CLL_LGenBase_TrafficFunctions all
import from EPTF_CLL_HashMapInt2Int_Functions all
import from EPTF_CLL_Logging_Functions all
import from EPTF_LGenBaseDemo_ResponderDefinitions all
import from EPTF_CLL_LGenBase_StepFunctions all
import from EPTF_LGenBaseDemo_CallerFunctions all
modulepar float tsp_targetCPS := 100.0
modulepar float tsp_maxDelay := 0.5
modulepar integer tsp_eGrpCount := 0
///////////////////////////////////////////////////////////////////////////////
// This is the starter function of the Responder component
///////////////////////////////////////////////////////////////////////////////
public function f_LGenBaseDemo_Responder_behavior(
in charstring pl_name,
in float pl_targetCPS,
in float pl_maxDelay)
runs on LGenBaseDemo_Responder_CT{
// This case there is no direct connection between the LGenBase entities
// and the simulated users. Therefore the minimal necessary amount of entities
// is target CPS * max. delay.
// Let's allocate a bit more...
var integer vl_eGrpSize := float2int(pl_targetCPS*pl_maxDelay*1.2)
if(0 < tsp_eGrpCount){
vl_eGrpSize := tsp_eGrpCount
}
// Initialize
f_LGenBaseDemo_Responder_init(pl_name, vl_eGrpSize, pl_maxDelay)
// Create the terminating scenario
// declared in the initialization
f_EPTF_LGenBase_createScenario2EntityGroup({c_LGenBaseDemo_Responder_entityGroupName,c_LGenBaseDemo_Responder_scenarioName})
v_LGenBaseDemo_Responder_responderTcIdx := f_EPTF_LGenBase_trafficCaseId(
c_LGenBaseDemo_Responder_entityGroupName,
c_LGenBaseDemo_Responder_scenarioName,
c_LGenBaseDemo_Responder_tcName)
// Come what may...
f_EPTF_Base_wait4Shutdown()
}
///////////////////////////////////////////////////////////////////////////////
// Initialize the Responder component
///////////////////////////////////////////////////////////////////////////////
public function f_LGenBaseDemo_Responder_init(
in charstring pl_name,
in integer pl_eGrpSize,
in float pl_maxDelay)
runs on LGenBaseDemo_Responder_CT{
f_LGenBaseDemo_Transport_init(
pl_name,
refers(f_LGenBaseDemo_Responder_processCallerMsgs))
f_EPTF_LGenBase_init(pl_name)
f_EPTF_Base_registerCleanup(refers(f_LGenBaseDemo_Responder_cleanup))
f_EPTF_int2int_HashMap_Init()
// This hashmap is used to identify which entity handles which response message.
// The acknowledgement message must be forwarded to the appropriate entity
v_LGenBaseDemo_Responder_msgHashMap := f_EPTF_int2int_HashMap_New(c_LGenBaseDemo_Responder_msgHashMapName)
// Create the background
// The behavior in the demo is used to identify
// - events
// - data related to the behavior
v_LGenBaseDemo_Responder_myBehavId := f_EPTF_LGenBase_declareBehaviorType(c_LGenBaseDemo_Responder_BehaviorName, -1, null, null, null)
f_EPTF_LGenBase_declareFsmEvent(c_LGenBaseDemo_Responder_BehaviorName, c_LGenBaseDemo_Responder_InputRegisterReceived)
f_EPTF_LGenBase_declareFsmEvent(c_LGenBaseDemo_Responder_BehaviorName, c_LGenBaseDemo_Responder_InputReRegisterReceived)
f_EPTF_LGenBase_declareFsmEvent(c_LGenBaseDemo_Responder_BehaviorName, c_LGenBaseDemo_Responder_InputDoMsgReceived)
f_EPTF_LGenBase_declareFsmEvent(c_LGenBaseDemo_Responder_BehaviorName, c_LGenBaseDemo_Responder_InputAckReceived)
// Declare the custom test step functions used in the responder FSMs
// To see their comments see the function definitions
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_reply2Register, refers(f_LGenBaseDemo_Responder_reply2Register)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_reply2ReRegister, refers(f_LGenBaseDemo_Responder_reply2ReRegister)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_reply2DoMsg, refers(f_LGenBaseDemo_Responder_Reply2DoMsg)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_delay, refers(f_LGenBaseDemo_Responder_Delay)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_watchdogTimerTimedOut, refers(f_LGenBaseDemo_Responder_WatchdogTimerTimedOut)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_storeMsg, refers(f_LGenBaseDemo_Responder_storeMsg)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_ackReceived, refers(f_LGenBaseDemo_Responder_ackReceived)})
f_EPTF_LGenBase_declareStep(c_LGenBaseDemo_Responder_BehaviorName, {c_LGenBaseDemo_Responder_StepName_inputInInvalidState, refers(f_LGenBaseDemo_Responder_InputInInvalidState)})
// Declare the custom function(s) used in the responder FSMs
f_EPTF_LGenBase_declareFunction(c_LGenBaseDemo_Responder_NextStateCalcName, {nextStateCalcFunction := refers(f_LGenBaseDemo_Responder_calcNextStateOfEvent)})
// Declare the group of entities used to simulate the users
f_EPTF_LGenBase_declareEntityType(c_LGenBaseDemo_Responder_entityTypeName, {c_LGenBaseDemo_Responder_BehaviorName})
f_EPTF_LGenBase_createEntityGroup({c_LGenBaseDemo_Responder_entityGroupName, c_LGenBaseDemo_Responder_entityTypeName, pl_eGrpSize})
//Declare the responder FSM
f_EPTF_LGenBase_declareFSMTable(f_LGenBaseDemo_ResponderFSM())
//Declare the traffic case type to use it in the scenario declaration
v_dummyInt := f_EPTF_LGenBase_declareTcType2(
{
name := c_LGenBaseDemo_Responder_tcName,
fsmName := c_LGenBaseDemo_Responder_fsmName,
entityType := c_LGenBaseDemo_Responder_entityTypeName,
customEntitySucc := ""
}
)
//Declare the scenario
//It's a simple responder, there is nothing interesting
f_EPTF_LGenBase_declareScenarioType3({
name := c_LGenBaseDemo_Responder_scenarioName,
tcList := {
{
tcName := c_LGenBaseDemo_Responder_tcName,
tcParamsList := {}
}
},
scParamsList := {
{trafficType := terminating}
}
})
}
///////////////////////////////////////////////////////////////////////////////
// Describes the FSM of the Responder.
//
// The basic flow is:
// - When a message arrives, the f_LGenBaseDemo_Responder_processCallerMsgs
// function dispatches an event, depending on the type of the message to
// the first available entity.
// - The FSM
// - notifies the LGenBase that it's started by an external event,
// - stores the received message into an FSM variable,
// - sets the timeout value of an FSM timer to a random value,
// - starts the timer, and
// - puts the FSM to a state depending on the type of the received message.
// - When the timer timed out, the Responder
// - sends out the appropriate response message, and
// - starts a watchdog timer
// - When the acknowledgement of the response message arrives, the FSM
// - cancels the watchdog timer, and
// - reports successful execution to free the entity, and
// - puts back the FSM to the "idle" state.
// - If the watchdog timed out, the FSM
// - reports timed out execution, and
// - puts back the FSM to the "idle" state.
//
// To demonstrate how to handle an event in separated FSM rows, the
// timeout of the "responseTimer" is handled in two rows.
// First row sends out the responses, the next row starts the watchdog.
///////////////////////////////////////////////////////////////////////////////
function f_LGenBaseDemo_ResponderFSM()
return EPTF_LGenBase_FsmTableDeclarator{
return {
name := c_LGenBaseDemo_Responder_fsmName,
fsmParams := {
{stateList := c_LGenBaseDemo_Responder_fsmStateList},
{varList := {
{
name := c_LGenBaseDemo_Responder_varNameOfLastMsg,
initValue := {charstringVal := ""},
scope := FSM
}}
},
{timerList := {
{name := "responseTimer", startValue := 0.1},
{name := "watchdog", startValue := c_LGenBaseDemo_Responder_Watchdog}
}}
},
table := {
extendedTable := {
{
//This row replies to the 'Register', 'ReRegister' and 'DoMsg' events
events2Listen := {
events := {
{
eventList := {
bName := c_LGenBaseDemo_Responder_BehaviorName,
iNameList := {
c_LGenBaseDemo_Responder_InputRegisterReceived,
c_LGenBaseDemo_Responder_InputReRegisterReceived,
c_LGenBaseDemo_Responder_InputDoMsgReceived
},
eventType := fsm
}
}
}
},
cellRow := {
statedCellRow := {
//If they arrive in the 'idle' state, it's OK
{ inState := { state := "idle"},
cell := { actionList := {
// Notify the LGenBase that the entity had been started by an external event.
{ stepOrFunctionName := c_EPTF_LGenBase_stepName_recordEntityStart, contextArgs := omit},
// Store the message content into an FSM variable, and
// the required next state to the behavior context of the entity.
// See the f_LGenBaseDemo_Responder_storeMsg function.
{ stepOrFunctionName := c_LGenBaseDemo_Responder_StepName_storeMsg, contextArgs := omit},
// Set the timeout value of the "responseTimer" to a random value.
{ stepOrFunctionName := c_LGenBaseDemo_Responder_StepName_delay, contextArgs := {timerName := "responseTimer"}},
// Start the timer
{ stepOrFunctionName := c_EPTF_LGenBase_stepName_timerStart, contextArgs := {timerName := "responseTimer"}}
},
// The next state calculation function gives back the state to put in the FSM
// based on the data stored by the f_LGenBaseDemo_Responder_storeMsg function.
// See the f_LGenBaseDemo_Responder_calcNextStateOfEvent function.
nextStateCalculation := {c_LGenBaseDemo_Responder_NextStateCalcName, omit},
nextState := omit
}},
//In any other state it's a programming fault.
{ inState := { anyUndefinedState := {}},
cell := { actionList := {
//Cancel all running FSM timers, orelse they'd cause errors!!!
{stepOrFunctionName := c_EPTF_LGenBase_stepName_cancelAllTimers,contextArgs := omit},
//Handle the error
{stepOrFunctionName := c_LGenBaseDemo_Responder_StepName_inputInInvalidState,contextArgs := omit},
// Report erroneous execution
{stepOrFunctionName := c_EPTF_LGenBase_stepName_trafficError,contextArgs := omit}
},
nextStateCalculation := omit,
nextState := "idle"
}}
}}
},
{
//Listens to the timeout of the started "responseTimer".
//This row sends out the responses. Since the responses
//are different in different states, the FSM handles the
//event in different cells.
//The next row listens to the same event in the same states,
//therefore this row leaves the FSM in its current state
events2Listen := { events := {{ singleEvent := {
bName := c_EPTF_LGenBase_specialBName_timerTimeout,
iName := "responseTimer",
eventType := fsm
}}}},
cellRow := { statedCellRow := {
{ inState := { state := "inRegister"},
cell := {
actionList := {
{c_LGenBaseDemo_Responder_StepName_reply2Register, omit}
},
//Stay in the same state yet
nextStateCalculation := omit,
nextState := omit
}},
{ inState := { state := "inReRegister"},
cell := { actionList := {
{c_LGenBaseDemo_Responder_StepName_reply2ReRegister, omit}
},
nextStateCalculation := omit,
nextState := omit
}},
{ inState := { state := "inDoMsg"},
cell := { actionList := {
{c_LGenBaseDemo_Responder_StepName_reply2DoMsg, omit}
},
nextStateCalculation := omit,
nextState := omit
}},
//In any other state it's a programming fault.
{ inState := { anyUndefinedState := {}},
cell := { actionList := {
{c_EPTF_LGenBase_stepName_cancelAllTimers, omit},
{c_LGenBaseDemo_Responder_StepName_inputInInvalidState, omit},
{c_EPTF_LGenBase_stepName_trafficError, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}}
}}
},
{
//Listens to the timeout of the started "responseTimer",
//just like the previous row. This case both rows will be processed
//in their declaration order.
//This row starts a watchdog timer in the
//states "inRegister","inReRegister","inDoMsg".
events2Listen := { events := {{ singleEvent := {
bName := c_EPTF_LGenBase_specialBName_timerTimeout,
iName := "responseTimer",
eventType := fsm
}}}},
cellRow := { statedCellRow := {
{ inState := { stateList := {"inRegister","inReRegister","inDoMsg"}},
cell := {
actionList := {
{c_EPTF_LGenBase_stepName_timerStart, {timerName := "watchdog"}}
},
nextStateCalculation := omit,
nextState := "waiting4Ack"
}}
}}
},
{
// Listens to the acknowledgment of the respons messages
events2Listen := { events := {{ singleEvent := {
bName := c_LGenBaseDemo_Responder_BehaviorName,
iName := c_LGenBaseDemo_Responder_InputAckReceived,
eventType := fsm
}}}},
cellRow := { statedCellRow := {
{ inState := { state := "waiting4Ack"},
cell := { actionList := {
// Cancel the watchdog timer
{c_EPTF_LGenBase_stepName_timerCancel, {timerName := "watchdog"}},
// Reply successful or failed execution
// depending on the content of the message
{c_LGenBaseDemo_Responder_StepName_ackReceived, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}},
{ inState := { anyUndefinedState := {}},
cell := { actionList := {
{c_EPTF_LGenBase_stepName_cancelAllTimers, omit},
{c_LGenBaseDemo_Responder_StepName_inputInInvalidState, omit}
// Don't report the finish of the execution here!
// Since the entity is not in state "waiting4Ack",
// Probably it isn't started or finished already.
// That would cause assertion fail.
//{c_EPTF_LGenBase_stepName_trafficError, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}}
}
}//cellRow
},
{
// Handle the watchdog timeout
events2Listen := { events := {{ singleEvent := {
bName := c_EPTF_LGenBase_specialBName_timerTimeout,
iName := "watchdog",
eventType := fsm
}}}},
cellRow := { statedCellRow := {
{ inState := { state := "waiting4Ack"},
cell := { actionList := {
{c_EPTF_LGenBase_stepName_trafficTimeout, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}},
{ inState := { anyUndefinedState := {}},
cell := { actionList := {
{c_EPTF_LGenBase_stepName_cancelAllTimers, omit},
{c_LGenBaseDemo_Responder_StepName_inputInInvalidState, omit},
{c_EPTF_LGenBase_stepName_trafficError, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}}
}
}//cellRow
},
{
// Handle all unexpected events
events2Listen := { unhandled := {}},
cellRow := { statedCellRow := {
{ inState := { anyUndefinedState := {}},
cell := { actionList := {
{c_EPTF_LGenBase_stepName_cancelAllTimers, omit},
{c_LGenBaseDemo_Responder_StepName_inputInInvalidState, omit},
{c_EPTF_LGenBase_stepName_trafficError, omit}
},
nextStateCalculation := omit,
nextState := "idle"
}}
}
}//cellRow
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// The Responder FSM starts a timer when a Caller message arrives, and
// puts the FSM to the appropriate state depending on the type of the
// incoming event.
// See the FSM declaration in the f_LGenBaseDemo_ResponderFSM function.
//
// This function returns the index of the state where the FSM must be put.
// See also the f_LGenBaseDemo_Responder_storeMsg function.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_state4Event(in integer pl_eventId)
runs on LGenBaseDemo_Responder_CT
return integer{
f_EPTF_Base_assert(%definitionId&": Invalid event ID:"&int2str(pl_eventId), pl_eventId > -1 and pl_eventId < sizeof(c_LGenBaseDemo_Responder_fsmStateList4Events))
return c_LGenBaseDemo_Responder_fsmStateList4Events[pl_eventId]
}
///////////////////////////////////////////////////////////////////////////////
// Handle the timeout.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_WatchdogTimerTimedOut(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
log(%definitionId&": The 'watchdog' timer timed out.")
}
///////////////////////////////////////////////////////////////////////////////
// Handle the case when an event arrives in a state where it shouldn't have come.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_InputInInvalidState(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
log(%definitionId&": '"&
f_EPTF_LGenBase_iIdx2Str(pl_args.reportedEvent.event.bIdx, pl_args.reportedEvent.event.iIdx)&
"' event arrived in state "&f_EPTF_LGenBase_getFsmStateNameByStepArgs(pl_args)&
". Entity#"&int2str(pl_args.eIdx))
}
///////////////////////////////////////////////////////////////////////////////
// Reports succesful or failed execution depending on the step arguments
// of the received event.
// This function demonstrates how to call step functions from step functions,
// and how to retrieve step arguments reported in the <f_EPTF_LGenBase_dispatchEvent>.
// See the f_LGenBaseDemo_Responder_processAck for the demo how to dispatch
// the event with step arguments.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_ackReceived(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
if(1 == pl_args.stepArgs[0]){
f_EPTF_LGenBase_step_trafficSuccess(pl_args)
}else{
f_EPTF_LGenBase_step_trafficFailed(pl_args)
}
}
///////////////////////////////////////////////////////////////////////////////
// Retrieves the content of a message. The content is stored in an FSM variable.
// See also the f_LGenBaseDemo_Responder_storeMsg function.
// This function demonstrates how to retrive the content of an FSM variable
// from an FSM step function.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_getLastMsg(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT
return charstring{
// Retrieve the name of the variable
// The variables of the FSMs have special names generated from the name declared
// in the FSM declaration. Don't create these names "manualy",
// use the function <f_EPTF_LGenBase_varNameOfFSMVar> instead.
var charstring vl_varNameOfMsg := f_EPTF_LGenBase_varNameOfFSMVar(
pl_args.eIdx,
pl_args.refContext.fCtxIdx,
c_LGenBaseDemo_Responder_varNameOfLastMsg)
//The ID from the name
var integer vl_varIdOfMsg := f_EPTF_Var_getId(vl_varNameOfMsg)
var EPTF_Var_DirectContent vl_content
//Get the content
f_EPTF_Var_getContent(vl_varIdOfMsg, vl_content)
return vl_content.charstringVal
}
///////////////////////////////////////////////////////////////////////////////
// This function demonstrates how to store simple temporary data during an
// FSM process
// It can be used when the data to be stored contains integer values.
// This case the data can be stored in the behavior context of the entity.
// This is a fast way.
//
// LGenBase provides also many more data storage methods.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_storeNextState(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
//Store the indices as behavior context data
f_EPTF_LGenBase_setBehaviorCtx(
pl_args.eIdx,
v_LGenBaseDemo_Responder_myBehavId,
{
pl_args.reportedEvent.event.iIdx,
f_LGenBaseDemo_Responder_state4Event(pl_args.reportedEvent.event.iIdx)
})
}
///////////////////////////////////////////////////////////////////////////////
// This function demonstrates how to store temporary data during an
// FSM process when the data to be stored contains other data than integer values.
// This case the data can be stored in an FSM variable.
// The data can be any type handled in the <EPTF_Var_DirectContent>.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_storeMsg(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
//Store the indices of the next state as behavior context data
f_EPTF_LGenBase_setBehaviorCtx(
pl_args.eIdx,
v_LGenBaseDemo_Responder_myBehavId,
{
pl_args.reportedEvent.event.iIdx,
f_LGenBaseDemo_Responder_state4Event(pl_args.reportedEvent.event.iIdx)
})
//Store the incoming message in an FSM variable
var charstring vl_varNameOfMsg := f_EPTF_LGenBase_varNameOfFSMVar(
pl_args.eIdx,
pl_args.refContext.fCtxIdx,
c_LGenBaseDemo_Responder_varNameOfLastMsg)
var integer vl_varIdOfMsg := f_EPTF_Var_getId(vl_varNameOfMsg)
var EPTF_Var_DirectContent vl_content
vl_content.charstringVal := f_LGenBaseDemo_Transport_getLastMsg()
f_EPTF_Var_adjustContent(vl_varIdOfMsg, vl_content)
}
///////////////////////////////////////////////////////////////////////////////
// Retrieves the data stored by the f_LGenBaseDemo_Responder_storeMsg
// function in the behavior context of the related entity.
///////////////////////////////////////////////////////////////////////////////
function f_LGenBaseDemo_Responder_calcNextStateOfEvent(
in integer eIdx,
in integer fIdx,
in EPTF_IntegerList contextArgs,
in EPTF_LGenBase_FsmTableCellReference pl_cell,
in EPTF_IntegerList pl_stepArgs)
runs on LGenBaseDemo_Responder_CT
return integer{
return f_EPTF_LGenBase_getBehaviorCtxItem(eIdx, v_LGenBaseDemo_Responder_myBehavId, c_LGenBaseDemo_Responder_behavCtxDataIdxNextStateIdx)
}
///////////////////////////////////////////////////////////////////////////////
// This function demonstrates how to set the timeout value of an FSM timer
// when the context argument contains the name of the timer.
//
// When the context argument has been declared in the FSM declaration as
// contextArgs := {timerName := "anyTimerName"}
// the 1st (idx==0) element of the fRefArgs <EPTF_IntegerList> field
// of the refContext field of the <EPTF_LGenBase_TestStepArgs>
// type pl_args parameter of the step function contains the index of the
// specified timer.
//
// See also <f_LGenBaseDemo_ResponderFSM>
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_Delay(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
//Get the timer idx
var integer vl_timerIdx := pl_args.refContext.fRefArgs[0]
//Set the duration
f_EPTF_LGenBase_setDuration4TimerAtFsmCtx(
pl_args.eIdx,
pl_args.refContext.fCtxIdx,
vl_timerIdx,
rnd()*v_LGenBaseDemo_Responder_maxDelay)
}
///////////////////////////////////////////////////////////////////////////////
// Gets the first available entity and dispatches an FSM event to it
// about the incoming external event.
// See also the f_LGenBaseDemo_Responder_processCallerMsgs function.
// The message ID - entity index relation is stored in a hashmap.
//
// Demonstrates how to
// - find an available (free) entity
// - get the FSM context index of an entity associated to a traffic case
// - dispatch an FSM event to a specific FSM
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_dispatchToEntity(in integer pl_inputId)
runs on LGenBaseDemo_Responder_CT{
var integer vl_eIdx := f_EPTF_LGenBase_getNextFreeEntity(v_LGenBaseDemo_Responder_responderTcIdx)
if(-1 < vl_eIdx){
var EPTF_LGenBase_ReportedEventDescriptor vl_event := c_EPTF_LGenBase_emptyReportedEventDescriptor
vl_event.event.bIdx := v_LGenBaseDemo_Responder_myBehavId
vl_event.event.iIdx := pl_inputId
vl_event.event.target.eIdx := vl_eIdx
vl_event.event.target.fsmCtxIdx := f_EPTF_LGenBase_getFSMCtxIdx(vl_eIdx, v_LGenBaseDemo_Responder_responderTcIdx)
log(%definitionId&": Event "&f_EPTF_LGenBase_iIdx2Str(v_LGenBaseDemo_Responder_myBehavId,pl_inputId)&
" dispatched to entity#"&int2str(vl_eIdx))
f_EPTF_LGenBase_dispatchEvent(vl_event)
}else{
//Error
log(%definitionId&": There is no free entity to process the message. Allocate more!")
f_EPTF_Base_stopAll(fail)
}
}
///////////////////////////////////////////////////////////////////////////////
// Processes an incoming acknowledgement message, and dispatches an FSM event
// about it. The value of the response code is dispatched in the step argument
// of the FSM event.
// Demonstrates how to
// - attach data to the step argument of the dispatched event
// - dispatch an event
// - get the FSM context index of an entity associated to a traffic case
// To see how to retrieve the step arguments see the
// f_LGenBaseDemo_Responder_ackReceived function.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_processAck(in LGenBaseDemo_MsgAck pl_msg)
runs on LGenBaseDemo_Responder_CT{
var integer vl_eIdx
log(%definitionId&": Ack message arrived: "&log2str(pl_msg))
//Get entity index from the message
if(not f_EPTF_int2int_HashMap_Find(v_LGenBaseDemo_Responder_msgHashMap, pl_msg.msgId, vl_eIdx)){
f_EPTF_Logging_warning(true,%definitionId&": Invalid message ID in Ack msg: "&log2str(pl_msg))
}else{
//Found
log(%definitionId&": The message handled by entity#"&int2str(vl_eIdx))
//Dispatch event to the FSM of the appropriate traffic case
var EPTF_LGenBase_ReportedEventDescriptor vl_event := c_EPTF_LGenBase_emptyReportedEventDescriptor
vl_event.event.bIdx := v_LGenBaseDemo_Responder_myBehavId
vl_event.event.iIdx := c_LGenBaseDemo_Responder_InputIdxAckReceived
vl_event.event.target.eIdx := vl_eIdx
vl_event.event.target.fsmCtxIdx := f_EPTF_LGenBase_getFSMCtxIdx(vl_eIdx, v_LGenBaseDemo_Responder_responderTcIdx)
//The result of the Ack will be passed through the reportedArgs
if(pl_msg.resp){
vl_event.reportedArgs := {1}
}else{
vl_event.reportedArgs := {0}
}
f_EPTF_int2int_HashMap_Erase(v_LGenBaseDemo_Responder_msgHashMap, pl_msg.msgId)
f_EPTF_LGenBase_dispatchEvent(vl_event)
}
}
///////////////////////////////////////////////////////////////////////////////
// The functions placed into this group have no demo content, but necessary
// for the application.
///////////////////////////////////////////////////////////////////////////////
group noDemoContent{
///////////////////////////////////////////////////////////////////////////////
// Send response to the Register message, and sets the registration state
// Sets the verdict to fail if a Register call arrived to a user already
// registered successfully.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_reply2Register(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
var boolean vl_resp := (rnd()<v_LGenBaseDemo_Responder_registerSuccessRate)
var charstring vl_msgIn := f_LGenBaseDemo_Responder_getLastMsg(pl_args)
var charstring vl_userData := f_LGenBaseDemo_Caller_getUserData(vl_msgIn)
var LGenBaseDemo_Transport_MessageData vl_msgData
f_LGenBaseDemo_Caller_decodeUserData(vl_msgIn, vl_msgData)
if(f_LGenBaseDemo_Responder_getUserState(vl_msgData.entityIdx)){
setverdict(fail, log2str("The user #"&int2str(vl_msgData.entityIdx)&" had been registered earlier."));
}else{
f_LGenBaseDemo_Responder_setUserStateSuccess(vl_msgData.entityIdx,vl_resp)
f_LGenBaseDemo_Responder_sendResponse(vl_userData, vl_resp, c_LGenBaseDemo_ResponseType_register, pl_args.eIdx)
}
}
///////////////////////////////////////////////////////////////////////////////
// Send response to the ReRegister message
// Sets the verdict to fail if a ReRegister call arrived, but the user had not
// been registered successfully.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_reply2ReRegister(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
var boolean vl_resp := (rnd()<v_LGenBaseDemo_Responder_reRegisterSuccessRate)
var charstring vl_msgIn := f_LGenBaseDemo_Responder_getLastMsg(pl_args)
var charstring vl_userData := f_LGenBaseDemo_Caller_getUserData(vl_msgIn)
var LGenBaseDemo_Transport_MessageData vl_msgData
f_LGenBaseDemo_Caller_decodeUserData(vl_msgIn, vl_msgData)
if(f_LGenBaseDemo_Responder_getUserState(vl_msgData.entityIdx)){
f_LGenBaseDemo_Responder_sendResponse(vl_userData, vl_resp, c_LGenBaseDemo_ResponseType_reRegister, pl_args.eIdx)
}else{
setverdict(fail, log2str("ReRegister received for user #"&int2str(vl_msgData.entityIdx)&" which had not been registered earlier."));
}
}
///////////////////////////////////////////////////////////////////////////////
// Send response to the DoMsg message
// Sets the verdict to fail if a ReRegister call arrived, but the user had not
// been registered successfully.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_Reply2DoMsg(in EPTF_LGenBase_TestStepArgs pl_args)
runs on LGenBaseDemo_Responder_CT{
var boolean vl_resp := (rnd()<v_LGenBaseDemo_Responder_doMsgSuccessRate)
var charstring vl_msgIn := f_LGenBaseDemo_Responder_getLastMsg(pl_args)
var charstring vl_userData := f_LGenBaseDemo_Caller_getUserData(vl_msgIn)
var LGenBaseDemo_Transport_MessageData vl_msgData
f_LGenBaseDemo_Caller_decodeUserData(vl_msgIn, vl_msgData)
log(%definitionId&log2str(vl_msgData), " ", vl_userData)
log(v_LGenBaseDemo_Responder_userStates[vl_msgData.entityIdx])
log(v_LGenBaseDemo_Responder_userStates)
if(f_LGenBaseDemo_Responder_getUserState(vl_msgData.entityIdx)){
f_LGenBaseDemo_Responder_sendResponse(vl_userData, vl_resp, c_LGenBaseDemo_ResponseType_doMsg, pl_args.eIdx)
}else{
setverdict(fail, "DoMsg received for user #"&int2str(vl_msgData.entityIdx)&" which had not been registered earlier.")
}
}
///////////////////////////////////////////////////////////////////////////////
// Returns the registration state of a user
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_getUserState(in integer pl_userIdx)
runs on LGenBaseDemo_Responder_CT
return boolean{
return isvalue(v_LGenBaseDemo_Responder_userStates[pl_userIdx]) and v_LGenBaseDemo_Responder_userStates[pl_userIdx]
}
///////////////////////////////////////////////////////////////////////////////
// Sets the registration state of a user
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_setUserStateSuccess(in integer pl_userIdx, in boolean pl_success)
runs on LGenBaseDemo_Responder_CT{
v_LGenBaseDemo_Responder_userStates[pl_userIdx] := pl_success
}
const float c_LGenBaseDemo_Responder_Watchdog := 0.5
///////////////////////////////////////////////////////////////////////////////
// Cleanup of the Responder component
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_cleanup()
runs on LGenBaseDemo_Responder_CT{
f_EPTF_int2int_HashMap_Delete(c_LGenBaseDemo_Responder_msgHashMapName)
v_LGenBaseDemo_Responder_msgHashMap := -1
}
///////////////////////////////////////////////////////////////////////////////
// Fills in a response message related to the message type, and
// sends out the message.
///////////////////////////////////////////////////////////////////////////////
public function f_LGenBaseDemo_Responder_sendResponse(
in charstring pl_msgUserData,
in boolean pl_response,
in LGenBaseDemo_ResponseType pl_msgType,
in integer pl_eIdx)
runs on LGenBaseDemo_Responder_CT{
var integer vl_msgId := v_LGenBaseDemo_Responder_msgCounter
v_LGenBaseDemo_Responder_msgCounter := v_LGenBaseDemo_Responder_msgCounter + 1
f_EPTF_int2int_HashMap_Insert(v_LGenBaseDemo_Responder_msgHashMap, vl_msgId, pl_eIdx)
var LGenBaseDemo_Msg vl_msg
select( pl_msgType ){
case ( c_LGenBaseDemo_ResponseType_register ){
vl_msg.registerResp.msgId := vl_msgId
vl_msg.registerResp.resp := pl_response
vl_msg.registerResp.msgUserData := pl_msgUserData
log(%definitionId&": Registration result: "&log2str(pl_response)&" UserData: "&pl_msgUserData)
}
case ( c_LGenBaseDemo_ResponseType_reRegister ){
vl_msg.reRegisterResp.msgId := vl_msgId
vl_msg.reRegisterResp.resp := pl_response
vl_msg.reRegisterResp.msgUserData := pl_msgUserData
}
case ( c_LGenBaseDemo_ResponseType_doMsg ){
vl_msg.doMsgResp.msgId := vl_msgId
vl_msg.doMsgResp.resp := pl_response
vl_msg.doMsgResp.msgUserData := pl_msgUserData
}
case else{
//TODO error
}
}
log(%definitionId&": The message_id#"&int2str(vl_msgId)&" is handled by entity#"&int2str(pl_eIdx))
f_LGenBaseDemo_Transport_sendMessage(vl_msg)
}
///////////////////////////////////////////////////////////////////////////////
// Processes an incoming message, and calls the
// f_LGenBaseDemo_Responder_dispatchToEntity function to dispatch the
// appropriate event to an entity.
///////////////////////////////////////////////////////////////////////////////
private function f_LGenBaseDemo_Responder_processCallerMsgs(in LGenBaseDemo_Msg pl_msg)
runs on LGenBaseDemo_Responder_CT{
log(%definitionId&": "&log2str(pl_msg))
if ( ischosen(pl_msg.register) ){
f_LGenBaseDemo_Responder_dispatchToEntity(c_LGenBaseDemo_Responder_InputIdxRegisterReceived)
}
else if ( ischosen(pl_msg.reRegister) ){
f_LGenBaseDemo_Responder_dispatchToEntity(c_LGenBaseDemo_Responder_InputIdxReRegisterReceived)
}
else if ( ischosen(pl_msg.doMsg) ){
f_LGenBaseDemo_Responder_dispatchToEntity(c_LGenBaseDemo_Responder_InputIdxDoMsgReceived)
}
else if ( ischosen(pl_msg.msgAck) ){
f_LGenBaseDemo_Responder_processAck(pl_msg.msgAck)
} else {
//TODO Error
}
}
}
} // end of module