blob: 1a21385ba0b6fff389a96528e55545330925bd54 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2020 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
///////////////////////////////////////////////////////////////////////////////
// File: EPTF_MQTT_LocalTransport_Definitions.ttcn
// Description:
// Rev: <RnXnn>
// Prodnr: CNL 113 860
// Updated: 2020-01-07
// Contact: http://ttcn.ericsson.se
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_MQTT_LGen_Functions
//
// Purpose:
// This module contains the functions of the MQTT load generator component
//
// See also:
// <EPTF_MQTT_LGen_Definitions>
///////////////////////////////////////////////////////////////
module EPTF_MQTT_LGen_Functions {
import from EPTF_MQTT_LGen_Definitions all;
import from EPTF_MQTT_Transport_Definitions all;
import from EPTF_CLL_Base_Functions all;
import from EPTF_CLL_Common_Definitions all;
import from EPTF_CLL_Variable_Definitions all;
import from EPTF_CLL_Variable_Functions all;
import from EPTF_CLL_LGenBase_Definitions all;
import from EPTF_CLL_LGenBase_ConfigFunctions all;
import from EPTF_CLL_LGenBase_Functions all;
import from EPTF_CLL_LGenBase_EventHandlingFunctions all;
import from EPTF_CLL_Logging_Definitions all;
import from EPTF_CLL_Logging_Functions all;
import from EPTF_CLL_FBQ_Functions all;
import from EPTF_CLL_HashMapStr2Int_Functions all;
import from EPTF_CLL_Scheduler_Definitions all;
import from EPTF_CLL_RBTScheduler_Functions all;
import from TCCConversion_Functions all;
import from MQTT_v3_1_1_Types all;
import from IPL4asp_Types all;
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_init
//
// Purpose:
// The main initialization function for the <EPTF_MQTT_LGen_CT> component type
//
// Parameters:
// pl_name - *in* *charstring* - the name for the component instance
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_init(in charstring pl_name)
runs on EPTF_MQTT_LGen_CT
{
if (v_MQTT_initialized){return;}
f_EPTF_LGenBase_init(pl_name, 0, pl_name);
f_EPTF_Logging_init_CT(pl_name);
f_EPTF_str2int_HashMap_Init();
v_MQTT_bIdx := f_EPTF_LGenBase_declareBehaviorType(
c_MQTT_behaviorType,
tsp_EPTF_MQTT_LGen_maxBindableCtx,
refers(f_MQTT_eCtxReset),
refers(f_MQTT_eCtxBind),
refers(f_MQTT_eCtxUnbind)
);
v_MQTT_loggingMaskId :=
f_EPTF_Logging_registerComponentMasks(
"MQTT_Logging",
{"WARNING", "DEBUG", "DEBUGV", "ERROR" },
EPTF_Logging_CLL);
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId,": my behavior idx is ", v_MQTT_bIdx));
f_EPTF_MQTT_addressDB_init();
f_EPTF_MQTT_templateDB_init();
f_EPTF_MQTT_sessionDB_init();
f_EPTF_MQTT_subscriptionDB_init();
f_EPTF_MQTT_publishDB_init();
f_EPTF_MQTT_declareSteps();
f_EPTF_MQTT_declareEvents();
f_EPTF_Base_registerCleanup(refers(f_MQTT_cleanUp));
v_MQTT_initialized := true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_initLogging
//
// Purpose:
// Initializing CLL's logging feature on the <EPTF_MQTT_LGen_CT> component type
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_initLogging()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_Logging_init_CT("MQTT_LGen");
v_MQTT_loggingMaskId :=
f_EPTF_Logging_registerComponentMasks(
"MQTT_LGen_Logging",
{"WARNING", "DEBUG", "DEBUGV", "ERROR"},
EPTF_Logging_CLL
);
if(tsp_EPTF_MQTT_LGen_debug){
f_EPTF_Logging_enableLocalMask(v_MQTT_loggingMaskId, c_MQTT_LGen_Logging_DEBUG);
}
else {
f_EPTF_Logging_disableLocalMask(v_MQTT_loggingMaskId, c_MQTT_LGen_Logging_DEBUG);
}
if(tsp_EPTF_MQTT_LGen_debugVerbose) {
f_EPTF_Logging_enableLocalMask(v_MQTT_loggingMaskId, c_MQTT_LGen_Logging_DEBUGV);
}
else {
f_EPTF_Logging_disableLocalMask(v_MQTT_loggingMaskId, c_MQTT_LGen_Logging_DEBUGV);
}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_cleanUp
//
// Purpose:
// The main clean up function for the <EPTF_MQTT_LGen_CT> component type
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_addressDB_cleanUp();
f_EPTF_MQTT_templateDB_cleanUp();
f_EPTF_MQTT_sessionDB_cleanUp();
f_EPTF_MQTT_subscriptionDB_cleanUp();
f_EPTF_MQTT_publishDB_cleanUp();
vf_MQTT_msgReceived := null;
v_MQTT_initialized := false;
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_eCtxBind
//
// Purpose:
// This function is called by the CLL for each entity instance created on a particular instace of <EPTF_MQTT_LGen_CT>
//
// Parameters:
// pl_eIdx - *in* *integer* - the index of the entity instance on this load generator component instance
//
// Returns:
// <EPTF_IntegerList> - The list will contain the index of the entity the context belongs to
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_eCtxBind(in integer pl_eIdx)
runs on EPTF_MQTT_LGen_CT
return EPTF_IntegerList
{
return {pl_eIdx};
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_eCtxUnbind
//
// Purpose:
// The reverse operation of <f_MQTT_eCtxBind>. Cleans up resources reserved during <f_MQTT_eCtxBind>. Called by the CLL.
//
// Parameters:
// pl_eIdx - *in* *integer* - the index of the entity instance on this load generator component instance
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_eCtxUnbind(in integer pl_eIdx)
runs on EPTF_MQTT_LGen_CT
{
if (not v_MQTT_initialized) {return;}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_eCtxReset
//
// Purpose:
// The resources reserved during <f_MQTT_eCtxBind> are reinitalized (reset). Called by the CLL.
//
// Parameters:
// pl_eIdx - *in* *integer* - the index of the entity instance on this load generator component instance
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_eCtxReset(in integer pl_eIdx)
runs on EPTF_MQTT_LGen_CT
{
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_declareEvents
//
// Purpose:
// Declares the FSM events to the CLL framework implemented by <EPTF_MQTT_LGen_CT>
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_declareEvents()
runs on EPTF_MQTT_LGen_CT
{
var integer vl_dummy;
if (
c_MQTT_eventIdx_transportSucc != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_transportSucc) or
c_MQTT_eventIdx_transportFail != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_transportFail) or
c_MQTT_eventIdx_transportClosed != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_transportClosed) or
c_MQTT_eventIdx_CONNACK_Accepted != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_CONNACK_Accepted) or
c_MQTT_eventIdx_CONNACK_Refused != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_CONNACK_Refused) or
c_MQTT_eventIdx_SUBACK_Accepted != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_SUBACK_Accepted) or
c_MQTT_eventIdx_SUBACK_Refused != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_SUBACK_Refused) or
c_MQTT_eventIdx_UNSUBACK != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_UNSUBACK) or
c_MQTT_eventIdx_PUBLISH != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBLISH) or
c_MQTT_eventIdx_PING_Request != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PING_Request) or
c_MQTT_eventIdx_PING_Response != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PING_Response) or
c_MQTT_eventIdx_PUBACK != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBACK) or
c_MQTT_eventIdx_PUBREC != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBREC) or
c_MQTT_eventIdx_PUBREL != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBREL) or
c_MQTT_eventIdx_PUBCOMP != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBCOMP) or
c_MQTT_eventIdx_PUBLISH_Timeout != f_EPTF_LGenBase_declareFsmEvent(c_MQTT_behaviorType, c_MQTT_eventName_PUBLISH_Timeout)
)
{
f_EPTF_LGenBase_log();
log("error"); mtc.stop
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_declareSteps
//
// Purpose:
// Declares the FSM steps to the CLL framework implemented by <EPTF_MQTT_LGen_CT>
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_declareSteps()
runs on EPTF_MQTT_LGen_CT
{
if (
c_MQTT_stepIdx_init != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_init, refers(f_MQTT_step_init)}) or
c_MQTT_stepIdx_cleanUp != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_cleanUp, refers(f_MQTT_step_cleanUp) }) or
c_MQTT_stepIdx_setLocalAddress_byVars != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setLocalAddress_byVars, refers(f_MQTT_step_setLocalAddress_byVars)}) or
c_MQTT_stepIdx_setRemoteAddress_byVars != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setRemoteAddress_byVars, refers(f_MQTT_step_setRemoteAddress_byVars)}) or
c_MQTT_stepIdx_transportConnect != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_transportConnect, refers(f_MQTT_step_transportConnect)}) or
c_MQTT_stepIdx_transportClose != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_transportClose, refers(f_MQTT_step_transportClose)}) or
c_MQTT_stepIdx_startListening != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_startListening, refers(f_MQTT_step_startListening)}) or
c_MQTT_stepIdx_loadTemplate_byIntIdx != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_loadTemplate_byIntIdx, refers(f_MQTT_step_loadTemplate_byIntIdx)}) or
c_MQTT_stepIdx_loadTemplate_byStringId != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_loadTemplate_byStringId, refers(f_MQTT_step_loadTemplate_byStringId)}) or
c_MQTT_stepIdx_send != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_send, refers(f_MQTT_step_send)}) or
c_MQTT_stepIdx_setTopic_stringParam != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setTopic_stringParam, refers(f_MQTT_step_setTopic_stringParam)}) or
c_MQTT_stepIdx_setTopic_add_stringParam != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setTopic_add_stringParam, refers(f_MQTT_step_setTopic_add_stringParam)}) or
c_MQTT_stepIdx_setTopic_add_varParams != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setTopic_add_varParams, refers(f_MQTT_step_setTopic_add_varParams)}) or
c_MQTT_stepIdx_setTopic_add_clientId != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setTopic_add_clientId, refers(f_MQTT_step_setTopic_add_clientId)}) or
c_MQTT_stepIdx_setQos_intParam != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setQos_intParam, refers(f_MQTT_step_setQos_intParam)}) or
c_MQTT_stepIdx_setPublishMessage_stringParam != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setPublishMessage_stringParam, refers(f_MQTT_step_setPublishMessage_stringParam)}) or
c_MQTT_stepIdx_setPublishMessage_add_stringParam != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setPublishMessage_add_stringParam, refers(f_MQTT_step_setPublishMessage_add_stringParam)}) or
c_MQTT_stepIdx_setPublishMessage_add_varParams != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setPublishMessage_add_varParams, refers(f_MQTT_step_setPublishMessage_add_varParams)}) or
c_MQTT_stepIdx_setPublishMessage_add_clientId != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_setPublishMessage_add_clientId, refers(f_MQTT_step_setPublishMessage_add_clientId)}) or
c_MQTT_stepIdx_reportPingResponse != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_reportPingResponse, refers(f_MQTT_step_reportPingResponse)}) or
c_MQTT_stepIdx_reportPublishResponse != f_EPTF_LGenBase_declareStep(c_MQTT_behaviorType,{c_MQTT_stepName_reportPublishResponse, refers(f_MQTT_step_reportPublishResponse)})
)
{
f_EPTF_LGenBase_log();
log("EPTF_MQTT_LGen declaration error"); mtc.stop
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_receiveMessage
//
// Purpose:
// The transport layer implementation <EPTF_MQTT_Transport_Provider_CT> can report received <EPTF_MQTT_PDU> message
// to the load generator layer <EPTF_MQTT_Transport_User_CT> extended by <EPTF_MQTT_LGen_CT> using this function.
//
// Parameters:
// pl_message - *in* <EPTF_MQTT_PDU> - received message
//
// Related Types:
// - <EPTF_MQTT_LGen_CT>
// - <fcb_EPTF_MQTT_Transport_receiveMessage>
// - <EPTF_MQTT_Transport_Provider_CT>
// - <EPTF_MQTT_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_receiveMessage(in EPTF_MQTT_PDU pl_message)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " ", pl_message));
v_MQTT_msgToProcess := pl_message;
f_EPTF_MQTT_stack_fromEnv(v_MQTT_msgToProcess);
if (vf_MQTT_msgReceived != null)
{
vf_MQTT_msgReceived.apply(v_MQTT_msgToProcess);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_receiveEvent
//
// Purpose:
// The transport layer implementation <EPTF_MQTT_Transport_Provider_CT> can report received <ASP_Event> events
// to the load generator layer <EPTF_MQTT_Transport_User_CT> extended by <EPTF_MQTT_LGen_CT> using this function.
//
// Parameters:
// pl_message - *in* <ASP_Event> - received event
//
// Related Types:
// - <EPTF_MQTT_LGen_CT>
// - <fcb_EPTF_MQTT_Transport_receiveEvent>
// - <EPTF_MQTT_Transport_Provider_CT>
// - <EPTF_MQTT_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_receiveEvent(in ASP_Event p_event)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " ", p_event));
// TODO: connection closed handling!
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_transportApiResponse
//
// Purpose:
// The transport layer implementation <EPTF_MQTT_Transport_Provider_CT> can report received <EPTF_MQTT_Transport_Response> responses
// to the load generator layer <EPTF_MQTT_Transport_User_CT> extended by <EPTF_MQTT_LGen_CT> using this function.
//
// Parameters:
// pl_rsp - *in* <EPTF_MQTT_Transport_Response> - received transport api response
//
// Related Types:
// - <EPTF_MQTT_LGen_CT>
// - <fcb_EPTF_MQTT_Transport_apiResponse>
// - <EPTF_MQTT_Transport_Provider_CT>
// - <EPTF_MQTT_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_transportApiResponse(in EPTF_MQTT_Transport_Response pl_rsp)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str("api response: ", pl_rsp));
if (f_EPTF_MQTT_sessionDB_get(pl_rsp.sessionIdx, v_MQTT_session))
{
if (pl_rsp.succ)
{
f_EPTF_MQTT_dispatchEvent(c_MQTT_eventIdx_transportSucc, v_MQTT_session.eIdx, v_MQTT_session.fsmIdx, {});
}
else
{
f_EPTF_MQTT_dispatchEvent(c_MQTT_eventIdx_transportFail, v_MQTT_session.eIdx, v_MQTT_session.fsmIdx, {});
}
}
else
{
f_EPTF_MQTT_Logging_VERBOSE(log2str("session not found for api response: ", pl_rsp));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_LGen_send
//
// Purpose:
// This function is used to send out a message of a <EPTF_MQTT_PDU> using the registered
// function <fcb_EPTF_MQTT_Transport_sendMessage> of the underlying transport layer instance.
//
// Parameters:
// p_msg - *intout* <EPTF_MQTT_PDU> - the message to be sent
//
// Related Types:
// <EPTF_MQTT_PDU>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_LGen_send(inout EPTF_MQTT_PDU p_msg)
runs on EPTF_MQTT_LGen_CT
{
vf_EPTF_MQTT_Transport_send.apply(p_msg);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_init
//
// Purpose:
// Test Step to dynamically allocate and initialize the MQTT FSM context for the caller FSM. Prerequisite to call any other MQTT test step.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_init>
// - <c_MQTT_stepName_init>
///////////////////////////////////////////////////////////
function f_MQTT_step_init(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
var integer vl_eIdx := pl_ptr.eIdx;
var integer vl_fsmIdx := pl_ptr.refContext.fCtxIdx;
var integer vl_newSessionIdx := -1;
if (f_EPTF_MQTT_isFsmInitialized(vl_eIdx, vl_fsmIdx, vl_newSessionIdx)) { return }
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId, ": initializing fsm ", vl_fsmIdx, " for entity ",vl_eIdx));
var MQTT_Session vl_session := c_MQTT_Session_init;
vl_session.eIdx := vl_eIdx;
vl_session.fsmIdx := pl_ptr.refContext.fCtxIdx;
vl_newSessionIdx := f_EPTF_MQTT_sessionDB_add(vl_session);
f_EPTF_LGenBase_setAppDataItemOfFsmCtx(vl_eIdx, vl_fsmIdx, v_MQTT_bIdx, c_MQTT_AppData_sessionIdx, vl_newSessionIdx);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_cleanUp
//
// Purpose:
// Test Step to free up the MQTT FSM context for the caller FSM. Frees up all allocated instances that were used by this FSM instance.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_cleanUp>
// - <c_MQTT_stepName_cleanUp>
///////////////////////////////////////////////////////////
function f_MQTT_step_cleanUp(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
var integer vl_eIdx:=pl_ptr.eIdx;
var integer vl_fsmIdx := pl_ptr.refContext.fCtxIdx;
var integer vl_sessionIdx := -1;
if (not f_EPTF_MQTT_isFsmInitialized(vl_eIdx, vl_fsmIdx, vl_sessionIdx))
{
f_EPTF_MQTT_Logging_DEBUG(%definitionId&": FSM has not been initialized");
return;
}
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId,": FSM database: ",v_MQTT_sessionDB.data[vl_sessionIdx]));
f_EPTF_MQTT_session_remove(vl_sessionIdx);
f_EPTF_LGenBase_setAppDataItemOfFsmCtx(vl_eIdx, vl_fsmIdx, v_MQTT_bIdx, c_MQTT_AppData_sessionIdx, -1);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_setLocalAddress_byVars
//
// Purpose:
// Test step to set the local address in the entity context.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args (1st param: remoteHost: charstring, 2nd param: remotePort: integer)
//
// Related Constants:
// - <c_MQTT_stepIdx_setLocalAddress_byVars>
// - <c_MQTT_stepName_setLocalAddress_byVars>
///////////////////////////////////////////////////////////
function f_MQTT_step_setLocalAddress_byVars(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var EPTF_IntegerList vl_varIds := {};
f_EPTF_LGenBase_fsmVarIdListFromStep(pl_ptr, vl_varIds);
if (sizeof(vl_varIds)==2)
{
var EPTF_Var_DirectContent vl_host, vl_port;
f_EPTF_Var_getContent(vl_varIds[0], vl_host);
f_EPTF_Var_getContent(vl_varIds[1], vl_port);
if (not ischosen(vl_host.charstringVal)) {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " first param is not charstring variable!"));
return;
}
if (not ischosen(vl_port.intVal)) {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " second param is not integer variable!"));
return;
}
f_EPTF_MQTT_addressDB_add(
{
hostName := vl_host.charstringVal,
portNumber := vl_port.intVal
},
v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx
);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " two variables are needed as params!"));
}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_setRemoteAddress_byVars
//
// Purpose:
// Test step to set the remote address in the FSM context.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args (1st param: remoteHost: charstring, 2nd param: remotePort: integer)
//
// Related Constants:
// - <c_MQTT_stepIdx_setRemoteAddress_byVars>
// - <c_MQTT_stepName_setRemoteAddress_byVars>
///////////////////////////////////////////////////////////
function f_MQTT_step_setRemoteAddress_byVars(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var EPTF_IntegerList vl_varIds := {};
f_EPTF_LGenBase_fsmVarIdListFromStep(pl_ptr, vl_varIds);
if (sizeof(vl_varIds)==2)
{
var EPTF_Var_DirectContent vl_host, vl_port;
f_EPTF_Var_getContent(vl_varIds[0], vl_host);
f_EPTF_Var_getContent(vl_varIds[1], vl_port);
if (not ischosen(vl_host.charstringVal)) {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " first param is not charstring variable!"));
return;
}
if (not ischosen(vl_port.intVal)) {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " second param is not integer variable!"));
return;
}
f_EPTF_MQTT_addressDB_add(
{
hostName := vl_host.charstringVal,
portNumber := vl_port.intVal
},
v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].remoteAddrIdx
);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " two variables are needed as params!"));
}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_startListening
//
// Purpose:
// The test step expects that a transport endpoint is set in the addressDB as a local address.
// The step will initiate allocating the local address associated with the current session in the MQTT context
// and call the callback function to start listening.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_startListening>
// - <c_MQTT_stepName_startListening>
//
// Related Steps:
// - <f_MQTT_step_setLocalAddress_byVars>
//
// Related Callback Function Type:
// <fcb_EPTF_MQTT_Transport_apiRequest>
///////////////////////////////////////////////////////////
function f_MQTT_step_startListening(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var EPTF_MQTT_Transport_Request vl_req := c_EPTF_MQTT_Transport_Request_init;
vl_req.sessionIdx := v_MQTT_ctx.sessionIdx;
f_EPTF_MQTT_addressDB_get(vl_req.params.startListening.localAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx);
vf_EPTF_MQTT_Transport_apiRequest.apply(vl_req);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_transportConnect
//
// Purpose:
// The test step expects that local and remote socket adresses are set in the addressDB.
// The step will initiate allocating the local and remote addresses associated with the current session in the MQTT context
// and call the callback function to establish a connection.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_transportConnect>
// - <c_MQTT_stepName_transportConnect>
//
// Related Events:
// - <c_MQTT_eventIdx_transportSucc>
// - <c_MQTT_eventIdx_transportFail>
//
// Related Steps:
// - <f_MQTT_step_setLocalAddress_byVars>
//
// Related Callback Function Type:
// <fcb_EPTF_MQTT_Transport_apiRequest>
///////////////////////////////////////////////////////////
function f_MQTT_step_transportConnect(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var EPTF_MQTT_Transport_Request vl_req := c_EPTF_MQTT_Transport_Request_init;
vl_req.sessionIdx := v_MQTT_ctx.sessionIdx;
f_EPTF_MQTT_addressDB_get(vl_req.params.connect_.localAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(vl_req.params.connect_.remoteAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].remoteAddrIdx);
vf_EPTF_MQTT_Transport_apiRequest.apply(vl_req);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_transportClose
//
// Purpose:
// The test step expects that a transport endpoint is set in the addressDB as a local address.
// The step will call the callback function to close the connection by the local address associated with the current session in the MQTT context.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args (1st param int: expectResponse (optional))
//
// Related Constants:
// - <c_MQTT_stepIdx_transportClose>
// - <c_MQTT_stepName_transportClose>
//
// Related Steps:
// - <f_MQTT_step_startListening>
// - <f_MQTT_step_transportConnect>
//
// Related Callback Function Type:
// <fcb_EPTF_MQTT_Transport_apiRequest>
///////////////////////////////////////////////////////////
function f_MQTT_step_transportClose(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var integer vl_expectResponseInt := 1;
var boolean vl_expectResponse := true;
if (f_EPTF_MQTT_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_expectResponseInt))
{
if (vl_expectResponseInt <= 0) { vl_expectResponse := false; }
}
if (v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx >= 0)
{
var EPTF_MQTT_Transport_Request vl_req := c_EPTF_MQTT_Transport_Request_init;
vl_req.sessionIdx := v_MQTT_ctx.sessionIdx;
vl_req.expectResponse := vl_expectResponse;
f_EPTF_MQTT_addressDB_get(vl_req.params.close.localAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx);
vf_EPTF_MQTT_Transport_apiRequest.apply(vl_req);
}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_loadTemplate_byIntIdx
//
// Purpose:
// Test step to load a <MQTT_Template> from <tsp_EPTF_MQTT_LGen_templates> into *v_MQTT_msgToSend*
// (which can be sent using the send test step) by its integer index in test step args.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_loadTemplate_byIntIdx>
// - <c_MQTT_stepName_loadTemplate_byIntIdx>
//
// Related Function:
// <f_MQTT_step_send>
///////////////////////////////////////////////////////////
function f_MQTT_step_loadTemplate_byIntIdx(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var integer vl_templateIdx := -1;
f_EPTF_MQTT_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_templateIdx);
f_EPTF_MQTT_templateDB_get(vl_templateIdx, v_MQTT_msgToSend.pdu);
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_loadTemplate_byStringId
//
// Purpose:
// Test step to load a <MQTT_Template> from <tsp_EPTF_MQTT_LGen_templates> into *v_MQTT_msgToSend*
// (which can be sent using the send test step) by its string Id.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_loadTemplate_byStringId>
// - <c_MQTT_stepName_loadTemplate_byStringId>
//
// Related Function:
// <f_MQTT_step_send>
///////////////////////////////////////////////////////////
function f_MQTT_step_loadTemplate_byStringId(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_templateId := f_EPTF_LGenBase_charstringValOfStep(pl_ptr);
var integer vl_templateIdx := f_EPTF_MQTT_templateDB_lookUp(vl_templateId);
if (vl_templateIdx >= 0)
{
f_EPTF_MQTT_templateDB_get(vl_templateIdx, v_MQTT_msgToSend.pdu);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find template with id: ", vl_templateId));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setTopic_stringParam
//
// Purpose:
// Test step to set the string value referred by the test step argument as the topic of the first subscription entry in SUBSCRIBE and PUBLISH messages.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: topic name charstring)
//
// Related Constants:
// - <c_MQTT_stepIdx_setTopic_stringParam>
// - <c_MQTT_stepName_setTopic_stringParam>
//
///////////////////////////////////////////////////////////
function f_MQTT_step_setTopic_stringParam(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_topic := f_EPTF_LGenBase_charstringValOfStep(pl_ptr);
if (ischosen(v_MQTT_msgToSend.pdu.subscribe)) {
if (sizeof(v_MQTT_msgToSend.pdu.subscribe.payload)>0) {
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter := f_charstr2unichar(vl_topic);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find first subscription entry: ", v_MQTT_msgToSend));
}
}
else if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.topic_name := f_charstr2unichar(vl_topic);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setTopic_add_stringParam
//
// Purpose:
// Test step to add the string value referred by the test step argument to the topic of the first subscription entry in SUBSCRIBE and PUBLISH messages.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: topic name charstring)
//
// Related Constants:
// - <c_MQTT_stepIdx_setTopic_add_stringParam>
// - <c_MQTT_stepName_setTopic_add_stringParam>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setTopic_add_stringParam(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_topic := f_EPTF_LGenBase_charstringValOfStep(pl_ptr);
if (ischosen(v_MQTT_msgToSend.pdu.subscribe)) {
if (sizeof(v_MQTT_msgToSend.pdu.subscribe.payload)>0) {
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter :=
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter &
f_charstr2unichar(vl_topic);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find first subscription entry: ", v_MQTT_msgToSend));
}
}
if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.topic_name :=
v_MQTT_msgToSend.pdu.publish.topic_name &
f_charstr2unichar(vl_topic);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setTopic_add_varParams
//
// Purpose:
// Test step to add the string value of variables referred by the test step argument to the topic of the first subscription entry in SUBSCRIBE and PUBLISH messages.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(params: variables)
//
// Related Constants:
// - <c_MQTT_stepIdx_setTopic_add_varParams>
// - <c_MQTT_stepName_setTopic_add_varParams>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setTopic_add_varParams(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_strToAdd := "";
var EPTF_IntegerList vl_varIds := {};
f_EPTF_LGenBase_fsmVarIdListFromStep(pl_ptr, vl_varIds);
for (var integer i:=0; i<sizeof(vl_varIds); i:=i+1)
{
var EPTF_Var_DirectContent vl_var;
f_EPTF_Var_getContent(vl_varIds[i], vl_var);
if (ischosen(vl_var.charstringVal)) {
vl_strToAdd := vl_strToAdd & vl_var.charstringVal;
}
else if (ischosen(vl_var.intVal)) {
vl_strToAdd := vl_strToAdd & int2str(vl_var.intVal);
}
}
if (ischosen(v_MQTT_msgToSend.pdu.subscribe)) {
if (sizeof(v_MQTT_msgToSend.pdu.subscribe.payload)>0) {
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter :=
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter &
f_charstr2unichar(vl_strToAdd);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find first subscription entry: ", v_MQTT_msgToSend));
}
}
else if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.topic_name :=
v_MQTT_msgToSend.pdu.publish.topic_name &
f_charstr2unichar(vl_strToAdd);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setTopic_add_clientId
//
// Purpose:
// Test step to add client ID in the current session to the topic in the first subscription in SUBSCRIBE and to PUBLISH message.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(param: clientId)
//
// Related Constants:
// - <c_MQTT_stepIdx_setTopic_add_clientId>
// - <c_MQTT_stepName_setTopic_add_clientId>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setTopic_add_clientId(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
if (ischosen(v_MQTT_msgToSend.pdu.subscribe)) {
if (sizeof(v_MQTT_msgToSend.pdu.subscribe.payload)>0) {
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter :=
v_MQTT_msgToSend.pdu.subscribe.payload[0].topic_filter &
f_charstr2unichar(v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].clientId);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find first subscription entry: ", v_MQTT_msgToSend));
}
}
if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.topic_name :=
v_MQTT_msgToSend.pdu.publish.topic_name &
f_charstr2unichar(v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].clientId);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setQos_intParam
//
// Purpose:
// Test step to set the QoS level in SUBSCRIBE and PUBLISH messages using test step arguments
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: qos level (0,1,2) integer)
//
// Related Constants:
// - <c_MQTT_stepIdx_setQos_intParam>
// - <c_MQTT_stepName_setQos_intParam>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setQos_intParam(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var integer vl_qos := -1;
f_EPTF_MQTT_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_qos);
if (vl_qos >=0 and vl_qos < 3)
{
if (ischosen(v_MQTT_msgToSend.pdu.subscribe)) {
if (sizeof(v_MQTT_msgToSend.pdu.subscribe.payload)>0) {
v_MQTT_msgToSend.pdu.subscribe.payload[0].requested_qos := f_EPTF_MQTT_qos_int2enum(vl_qos);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Couldn't find first subscription entry: ", v_MQTT_msgToSend));
}
}
else if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.header.qos_level := f_EPTF_MQTT_qos_int2enum(vl_qos);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid qos level: ", vl_qos));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setPublishMessage_stringParam
//
// Purpose:
// Test step to set the content of the payload in PUBLISH message.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: publish message charstring)
//
// Related Constants:
// - <c_MQTT_stepIdx_setPublishMessage_stringParam>
// - <c_MQTT_stepName_setPublishMessage_stringParam>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setPublishMessage_stringParam(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_msg := f_EPTF_LGenBase_charstringValOfStep(pl_ptr);
if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.payload := char2oct(vl_msg);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setPublishMessage_add_stringParam
//
// Purpose:
// Test step to concatenate a string to the content of the PUBLISH message
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: publish message charstring)
//
// Related Constants:
// - <c_MQTT_stepIdx_setPublishMessage_add_stringParam>
// - <c_MQTT_stepName_setPublishMessage_add_stringParam>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
////////////////////////////////////////////////////////////
function f_MQTT_step_setPublishMessage_add_stringParam(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var charstring vl_msg := f_EPTF_LGenBase_charstringValOfStep(pl_ptr);
if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.payload :=
v_MQTT_msgToSend.pdu.publish.payload &
char2oct(vl_msg);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setPublishMessage_add_varParams
//
// Purpose:
// Test step to add the content of a set of variables to the payload of a PUBLISH message.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(params: variables)
//
// Related Constants:
// - <c_MQTT_stepIdx_setPublishMessage_add_varParams>
// - <c_MQTT_stepName_setPublishMessage_add_varParams>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setPublishMessage_add_varParams(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
if (not ischosen(v_MQTT_msgToSend.pdu.publish)) {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
return;
}
var charstring vl_strToAdd := "";
var EPTF_IntegerList vl_varIds := {};
f_EPTF_LGenBase_fsmVarIdListFromStep(pl_ptr, vl_varIds);
for (var integer i:=0; i<sizeof(vl_varIds); i:=i+1)
{
var EPTF_Var_DirectContent vl_var;
f_EPTF_Var_getContent(vl_varIds[i], vl_var);
if (ischosen(vl_var.charstringVal)) {
vl_strToAdd := vl_strToAdd & vl_var.charstringVal;
}
else if (ischosen(vl_var.intVal)) {
vl_strToAdd := vl_strToAdd & int2str(vl_var.intVal);
}
}
v_MQTT_msgToSend.pdu.publish.payload :=
v_MQTT_msgToSend.pdu.publish.payload &
char2oct(vl_strToAdd);
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_setPublishMessage_add_clientId
//
// Purpose:
// Test step to add client ID of the current session to the payload of a PUBLISH message.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(param: clientId)
//
// Related Constants:
// - <c_MQTT_stepIdx_setPublishMessage_add_clientId>
// - <c_MQTT_stepName_setPublishMessage_add_clientId>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_setPublishMessage_add_clientId(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
if (ischosen(v_MQTT_msgToSend.pdu.publish)) {
v_MQTT_msgToSend.pdu.publish.payload :=
v_MQTT_msgToSend.pdu.publish.payload &
char2oct(v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].clientId);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid message type in msgToSend: ", v_MQTT_msgToSend));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_reportPingResponse
//
// Purpose:
// Test step to set the report ping response to enable/disable using using step arguments.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args - 1:enable, 0:disable
//
// Related Constants:
// - <c_MQTT_stepIdx_reportPingResponse>
// - <c_MQTT_stepName_reportPingResponse>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_reportPingResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var integer vl_enable := -1;
f_EPTF_MQTT_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_enable);
if (vl_enable >=0 and vl_enable < 2)
{
v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].reportPingResponse := (vl_enable == 1);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid parameter: ", vl_enable));
}
}
/////////////////////////////////////////////////////////////
// Function: f_MQTT_step_reportPublishResponse
//
// Purpose:
// Test step to set the report publish response to enable/disable using step arguments
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args(1st param: enable (1)/disable (0): integer)
//
// Related Constants:
// - <c_MQTT_stepIdx_reportPublishResponse>
// - <c_MQTT_stepName_reportPublishResponse>
//
// Related Type:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_MQTT_step_reportPublishResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
var integer vl_enable := -1;
f_EPTF_MQTT_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_enable);
if (vl_enable >=0 and vl_enable < 2)
{
v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].reportPublishResponse := (vl_enable == 1);
}
else {
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId," Invalid parameter: ", vl_enable));
}
}
///////////////////////////////////////////////////////////
// Function: f_MQTT_step_send
//
// Purpose:
// Test step to send out an MQTT message from *v_MQTT_msgToSend*.
// The message will be processed by the Applib's MQTT stack
// The step expects the localAddress and the remoteAddress to be configured in addressDB.
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
//
// Related Constants:
// - <c_MQTT_stepIdx_send>
// - <c_MQTT_stepName_send>
//
// Related Functions:
// - <f_MQTT_step_loadTemplate_byIntIdx>
// - <f_MQTT_step_loadTemplate_byStringId>
//
// Related functions:
// <f_EPTF_MQTT_stack_fromApp>
///////////////////////////////////////////////////////////
function f_MQTT_step_send(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId," ",pl_ptr));
if (not f_EPTF_MQTT_setStepCtx(pl_ptr, v_MQTT_ctx)) { return; }
f_EPTF_MQTT_addressDB_get(v_MQTT_msgToSend.transportParams.localAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(v_MQTT_msgToSend.transportParams.remoteAddress, v_MQTT_sessionDB.data[v_MQTT_ctx.sessionIdx].remoteAddrIdx);
v_MQTT_msgToSend.transportParams.proto := {tcp := {}};
v_MQTT_msgToSend.sessionIdx := v_MQTT_ctx.sessionIdx;
f_EPTF_MQTT_Logging_DEBUG(log2str(%definitionId," msg to send: ",v_MQTT_msgToSend));
f_EPTF_MQTT_stack_fromApp(v_MQTT_msgToSend, v_MQTT_ctx);
f_EPTF_SchedulerComp_refreshSnapshotTime();
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_init
//
// Purpose:
// Function to initialize the addressDB
//
// Parameters:
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_init()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_addressDB.queue);
v_MQTT_addressDB.data := {};
v_MQTT_addressDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_MQTT_addressDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_cleanUp
//
// Purpose:
// Function to clean up the address database and release its resources
//
// Parameters:
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_addressDB.queue);
v_MQTT_addressDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_MQTT_addressDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_add
//
// Purpose:
// Add a socket address to the addressDB and return its index if no such entry yet,
// or return its index if already exists
//
// Parameters:
// p_addr - *in* <Socket> - socket address
// p_idx - *inout* *integer* - index of the address entry
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_add(in Socket p_addr, inout integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
p_idx := f_EPTF_MQTT_addressDB_lookUp(p_addr);
if (p_idx == -1)
{
p_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_MQTT_addressDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_MQTT_addressDB.queue);
f_EPTF_MQTT_Logging_DEBUG(log2str(": "," adding target address ", p_idx, " ", p_addr));
f_EPTF_str2int_HashMap_Insert(v_MQTT_addressDB.hashRef, f_EPTF_MQTT_addressDB_Socket2String(p_addr), p_idx);
v_MQTT_addressDB.data[p_idx] := p_addr;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_get
//
// Purpose:
// Get a socket address from the addressDB by its index
//
// Parameters:
// p_addr - *inout* <Socket> - returned socket address
// p_idx - *in* *integer* - index of the address to get
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_get(inout Socket p_addr, in integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
if (p_idx < sizeof(v_MQTT_addressDB.data) and p_idx >=0)
{
p_addr := v_MQTT_addressDB.data[p_idx];
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(": "," couldn't get address at ", p_idx));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_lookUp
//
// Purpose:
// Get the index of a socket entry in addressDB
//
// Parameters:
// p_sock - *in* <Socket> - socket address
//
// Return Type:
// *integer* - The index of the socket entry
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_lookUp(in Socket p_sock)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(v_MQTT_addressDB.hashRef, f_EPTF_MQTT_addressDB_Socket2String(p_sock), vl_idx);
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_addressDB_Socket2String
//
// Purpose:
// Converts a socket address in <Socket> type format to the string format "<IP address>:<port number>" to be used as hash key
//
// Parameters:
// p_sock - *inout* <Socket> - socket address
//
// Return Type:
// *charstring* - Socket address in string format
//
// Related Type:
// <MQTT_Address_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_addressDB_Socket2String(Socket p_sock)
return charstring
{
return p_sock.hostName&":"&int2str(p_sock.portNumber);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_templateDB_init
//
// Purpose:
// Initializes the *v_MQTT_templateDB* <MQTT_Template_DB> database by adding the templates given in <tsp_EPTF_MQTT_LGen_templates>
//
// Related Type:
// <MQTT_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_templateDB_init()
runs on EPTF_MQTT_LGen_CT
{
v_MQTT_templateDB.data := {};
v_MQTT_templateDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_MQTT_templateDB_Hash");
for (var integer i:=0; i<sizeof(tsp_EPTF_MQTT_LGen_templates); i:=i+1) {
f_EPTF_MQTT_templateDB_add(tsp_EPTF_MQTT_LGen_templates[i]);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_templateDB_add
//
// Purpose:
// Adds a new element to the *v_MQTT_templateDB* <MQTT_Template_DB> database
//
// Parameters:
// p_template - *in* <MQTT_Template> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <MQTT_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_templateDB_add(in MQTT_Template p_template)
runs on EPTF_MQTT_LGen_CT
return integer
{
if (f_EPTF_MQTT_templateDB_lookUp(p_template.id)!=-1)
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " template is already added with id: ", p_template.id));
return -1;
}
var integer v_idx := sizeof(v_MQTT_templateDB.data);
v_MQTT_templateDB.data[v_idx] := p_template;
f_EPTF_str2int_HashMap_Insert(v_MQTT_templateDB.hashRef, p_template.id, v_idx);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " template was added with id: ", p_template.id, " at idx: ",v_idx));
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_templateDB_lookUp
//
// Purpose:
// Gets the index of an <MQTT_Template> element in *v_MQTT_templateDB* <MQTT_Template_DB> database
//
// Parameters:
// p_id - *in* *charstring* - the id of the <MQTT_Template>
//
// Returns:
// *integer* - the index of the searched template in the database, or -1 if not found
//
// Related Type:
// <MQTT_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_templateDB_lookUp(in charstring p_id)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
if (not f_EPTF_str2int_HashMap_Find(v_MQTT_templateDB.hashRef, p_id, vl_idx))
{
vl_idx := -1;
}
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_templateDB_get
//
// Purpose:
// Retrieves an element from the *v_MQTT_templateDB* <MQTT_Template_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
// p_pdu - *inout* <MQTT_v3_1_1_ReqResp> - the retrieved element
//
// Related Type:
// <MQTT_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_templateDB_get(in integer p_idx, inout MQTT_v3_1_1_ReqResp p_pdu)
runs on EPTF_MQTT_LGen_CT
{
if (p_idx < sizeof(v_MQTT_templateDB.data) and p_idx >= 0)
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " template is fetched with idx: ", p_idx));
p_pdu := v_MQTT_templateDB.data[p_idx].msg;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_templateDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_MQTT_templateDB* <MQTT_Template_DB> database
//
// Related Type:
// <MQTT_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_templateDB_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
v_MQTT_templateDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_MQTT_templateDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_init
//
// Purpose:
// Initializes the *v_MQTT_sessionDB* <MQTT_Session_DB> database and adds its hash to *v_MQTT_sessionDB.hashRef*
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_init()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_sessionDB.queue);
v_MQTT_sessionDB.data := {};
v_MQTT_sessionDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_MQTT_sessionDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_MQTT_sessionDB* <MQTT_Session_DB> database
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_sessionDB.queue);
v_MQTT_sessionDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_MQTT_sessionDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_add
//
// Purpose:
// Adds a new element to the *v_MQTT_sessionDB* <MQTT_Session_DB> database
//
// Parameters:
// p_session - *in* <MQTT_Session> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_add(in MQTT_Session p_session)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_MQTT_sessionDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_MQTT_sessionDB.queue);
f_EPTF_MQTT_Logging_DEBUG(log2str(": "," adding session ", v_idx, " ", p_session));
v_MQTT_sessionDB.data[v_idx] := p_session;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_setKey
//
// Purpose:
// Sets the hash of the local socket address of a session by the session index
//
// Parameters:
// p_idx - *in* *integer* - the session index
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_setKey(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
if (f_EPTF_MQTT_sessionDB_get(p_idx, v_MQTT_session))
{
var Socket v_addr;
f_EPTF_MQTT_addressDB_get(v_addr, v_MQTT_session.localAddrIdx);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "setting key for sock: ",f_EPTF_MQTT_sessionDB_addrHash(v_addr)," idx: ",p_idx));
f_EPTF_str2int_HashMap_Insert(v_MQTT_sessionDB.hashRef, f_EPTF_MQTT_sessionDB_addrHash(v_addr), p_idx);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_lookUp
//
// Purpose:
// Gets the index of a session in *v_MQTT_sessionDB* <MQTT_Session_DB> database by its socket address
//
// Parameters:
// p_sock - *in* <Socket> - the socket address to look up
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_lookUp(in Socket p_sock)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(v_MQTT_sessionDB.hashRef, f_EPTF_MQTT_sessionDB_addrHash(p_sock), vl_idx);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "looked up sock: ",f_EPTF_MQTT_sessionDB_addrHash(p_sock)," idx: ",vl_idx));
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_get
//
// Purpose:
// Retrieves a session's data from the *v_MQTT_sessionDB* <MQTT_Session_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
// p_session - *inout* <MQTT_Session> - the retrieved session context
//
// Returns:
// *boolean* - true if OK, false if no session element with this index
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_get(in integer p_idx, inout MQTT_Session p_session)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_sessionDB.data) and p_idx >= 0)
{
p_session := v_MQTT_sessionDB.data[p_idx];
return true;
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "couldn't get session with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_check
//
// Purpose:
// Checks if a session element exists in the *v_MQTT_sessionDB* <MQTT_Session_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be checked
//
// Returns:
// boolean - true if the session exists
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_check(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_sessionDB.data) and p_idx >= 0 and f_EPTF_FBQ_itemIsBusy(p_idx, v_MQTT_sessionDB.queue))
{
return true;
}
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "invalid subscription with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_remove
//
// Purpose:
// Removes an element from the *v_MQTT_sessionDB* <MQTT_Session_DB> database and releases its resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <MQTT_Session_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_remove(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "removing session with idx: ", p_idx));
var Socket v_addr;
f_EPTF_MQTT_addressDB_get(v_addr, v_MQTT_sessionDB.data[p_idx].localAddrIdx);
f_EPTF_str2int_HashMap_Erase(v_MQTT_sessionDB.hashRef, f_EPTF_MQTT_sessionDB_addrHash(v_addr));
v_MQTT_sessionDB.data[p_idx] := c_MQTT_Session_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_MQTT_sessionDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_sessionDB_addrHash
//
// Purpose:
// Converts a socket address in <Socket> type format to the string format "<IP address>:<port number>" to be used as a hash key
//
// Parameters:
// p_sock - *in* <Socket> - socket address
//
// Returns:
// charstring - socket address in string format
//
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_sessionDB_addrHash(in Socket p_sock)
return charstring
{
return p_sock.hostName&":"&int2str(p_sock.portNumber);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_init
//
// Purpose:
// Initializes the *v_MQTT_publishDB* <MQTT_Publish_DB> database and creates its hashmap
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_init()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_publishDB.queue);
v_MQTT_publishDB.data := {};
v_MQTT_publishDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_MQTT_publishDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_MQTT_publishDB* <MQTT_Publish_DB> database
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_publishDB.queue);
v_MQTT_publishDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_MQTT_publishDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_add
//
// Purpose:
// Adds a new element to the *v_MQTT_publishDB* <MQTT_Publish_DB> database
//
// Parameters:
// p_pub - *in* <MQTT_Publish> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_add(in MQTT_Publish p_pub)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_MQTT_publishDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_MQTT_publishDB.queue);
f_EPTF_MQTT_Logging_DEBUG(log2str(": "," adding publish ", v_idx, " ", p_pub));
f_EPTF_str2int_HashMap_Insert(
v_MQTT_publishDB.hashRef,
f_EPTF_MQTT_publishDB_packetIdHash(p_pub.sessionIdx, p_pub.packetId),
v_idx
);
v_MQTT_publishDB.data[v_idx] := p_pub;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_lookUp
//
// Purpose:
// Gets the index of an <MQTT_Publish> element in *v_MQTT_publishDB* <MQTT_Publish_DB> database by its session and packet id-s
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session id
// p_packetId - *in* *integer* - input packet id
//
// Returns:
// *integer* - the index of the searched element in the database, or -1 if not found
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_lookUp(in integer p_sessionIdx, in integer p_packetId)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(
v_MQTT_publishDB.hashRef,
f_EPTF_MQTT_publishDB_packetIdHash(p_sessionIdx, p_packetId),
vl_idx
);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "looked up publish idx: ",vl_idx));
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_get
//
// Purpose:
// Retrieves an element from the *v_MQTT_publishDB* <MQTT_Publish_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
// p_pub - *inout* <MQTT_Publish> - the retrieved element
//
// Returns:
// boolean - true: success, false: no element with the index p_idx
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_get(in integer p_idx, inout MQTT_Publish p_pub)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_publishDB.data) and p_idx >= 0)
{
p_pub := v_MQTT_publishDB.data[p_idx];
return true;
}
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "couldn't get publish with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_check
//
// Purpose:
// Checks if an element exists in the *v_MQTT_publishDB* <MQTT_Publish_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be checked
//
// Returns:
// boolean - true: element present, false: element doesn't exists
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_check(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_publishDB.data) and p_idx >= 0 and f_EPTF_FBQ_itemIsBusy(p_idx, v_MQTT_publishDB.queue))
{
return true;
}
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "invalid publish with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_remove
//
// Purpose:
// Removes an element from the *v_MQTT_publishDB* <MQTT_Publish_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be Removed
//
// Related Type:
// <MQTT_Publish_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_remove(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " removing idx: ", p_idx));
if (f_EPTF_MQTT_publishDB_get(p_idx, v_MQTT_publish))
{
f_EPTF_str2int_HashMap_Erase(
v_MQTT_publishDB.hashRef,
f_EPTF_MQTT_publishDB_packetIdHash(
v_MQTT_publish.sessionIdx,
v_MQTT_publish.packetId)
);
v_MQTT_publishDB.data[p_idx] := c_MQTT_Publish_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_MQTT_publishDB.queue);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishDB_packetIdHash
//
// Purpose:
// Converts a pair of session ID & packet ID to the string format "session_<sessionId>:id_<packetId>" to be used as a hash key
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session ID
// p_packetId - *in* *integer* - input packet ID
//
// Returns:
// charstring - converted IDs
//
// Related Type:
// <MQTT_Publish_DB>
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishDB_packetIdHash(in integer p_sessionIdx, in integer p_packetId)
return charstring
{
return "session_"&int2str(p_sessionIdx)&":"&"id_"&int2str(p_packetId);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_init
//
// Purpose:
// Initializes the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_init()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_subscriptionDB.queue);
v_MQTT_subscriptionDB.data := {};
v_MQTT_subscriptionDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_MQTT_subscriptionDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_cleanUp()
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_MQTT_subscriptionDB.queue);
v_MQTT_subscriptionDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_MQTT_subscriptionDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_add
//
// Purpose:
// Adds a new element to the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Parameters:
// p_sub - *in* <MQTT_Subscription> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_add(in MQTT_Subscription p_sub)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_MQTT_subscriptionDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_MQTT_subscriptionDB.queue);
f_EPTF_MQTT_Logging_DEBUG(log2str(": "," adding subscription ", v_idx, " ", p_sub));
if (ispresent(p_sub.request))
{
f_EPTF_str2int_HashMap_Insert(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_packetIdHash(p_sub.sessionIdx, p_sub.request.packet_identifier),
v_idx
);
// TODO: Only the first topic name will be used!
// TODO: It is not checked if there is already a subscription for this!
if (sizeof(p_sub.request.payload)>0)
{
var universal charstring vl_topicName := p_sub.request.payload[0].topic_filter;
f_EPTF_str2int_HashMap_Insert(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_topicHash(p_sub.sessionIdx, f_unichar2charstr(vl_topicName)),
v_idx
);
}
}
v_MQTT_subscriptionDB.data[v_idx] := p_sub;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_setKey_packetId
//
// Purpose:
// Insert an integer element to the subscription hashmap, key is composed from session ID and packet ID
//
// Parameters:
// p_idx - *in* *integer* - data to be inserted
// p_sessionIdx - *in* *integer* - input session ID, used in hashmap key
// p_packetId - *in* *integer* - input packet ID, used in hashmap key
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_setKey_packetId(in integer p_idx, in integer p_sessionIdx, in integer p_packetId)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_str2int_HashMap_Insert(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_packetIdHash(p_sessionIdx, p_packetId),
p_idx
);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_removeKey_packetId
//
// Removes the element from the subscription hashmap identified by its session ID and packet ID
//
// Parameters:
// p_idx - *in* *integer* - NOT USED
// p_sessionIdx - *in* *integer* - input session ID, used in hashmap key
// p_packetId - *in* *integer* - input packet ID, used in hashmap key
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_removeKey_packetId(in integer p_idx, in integer p_sessionIdx, in integer p_packetId)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_str2int_HashMap_Erase(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_packetIdHash(p_sessionIdx, p_packetId)
);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_lookUp_packetId
//
// Purpose:
// Gets the index of an <MQTT_Subscription> element in *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
// by a session ID and packet ID
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session ID, used in hashmap key
// p_packetId - *in* *integer* - input packet ID, used in hashmap key
//
// Returns:
// *integer* - the index of the searched element in the database, or -1 if not found
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_lookUp_packetId(in integer p_sessionIdx, in integer p_packetId)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_packetIdHash(p_sessionIdx, p_packetId),
vl_idx
);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "looked up subscription idx: ",vl_idx));
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_lookUp_topicName
//
// Purpose:
// Gets the index of an <MQTT_Subscription> element in *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
// by a session ID and packet ID
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session ID, used in hashmap key
// p_topicName - *in* *charstring* - input topic, used in hashmap key
//
// Returns:
// *integer* - the index of the searched element in the database, or -1 if not found
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_lookUp_topicName(in integer p_sessionIdx, in charstring p_topicName)
runs on EPTF_MQTT_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_topicHash(p_sessionIdx, p_topicName),
vl_idx
);
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, "looked up subscription idx: ",vl_idx));
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_get
//
// Purpose:
// Retrieves an element from the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
// p_sub - *inout* <MQTT_Subscription> - the retrieved element
//
// Returns:
// *boolean* - true: success, false: element with this index doesn't exist
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_get(in integer p_idx, inout MQTT_Subscription p_sub)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_subscriptionDB.data) and p_idx >= 0)
{
p_sub := v_MQTT_subscriptionDB.data[p_idx];
return true;
}
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "couldn't get subscription with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_check
//
// Purpose:
// Checks if an element at an index exists the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be checked
//
// Returns:
// *boolean* - true: success, false: element at this index is not present
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_check(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (p_idx < sizeof(v_MQTT_subscriptionDB.data) and p_idx >= 0 and f_EPTF_FBQ_itemIsBusy(p_idx, v_MQTT_subscriptionDB.queue))
{
return true;
}
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, "invalid subscription with idx: ", p_idx));
return false;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_remove
//
// Purpose:
// Removes an element from the *v_MQTT_subscriptionDB* <MQTT_Subscription_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_remove(in integer p_idx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " removing idx: ", p_idx));
if (f_EPTF_MQTT_subscriptionDB_get(p_idx, v_MQTT_subscription))
{
if (ispresent(v_MQTT_subscription.request))
{
f_EPTF_str2int_HashMap_Erase(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_packetIdHash(
v_MQTT_subscription.sessionIdx,
v_MQTT_subscription.request.packet_identifier)
);
}
if (sizeof(v_MQTT_subscription.request.payload)>0)
{
var universal charstring vl_topicName := v_MQTT_subscription.request.payload[0].topic_filter;
f_EPTF_str2int_HashMap_Erase(
v_MQTT_subscriptionDB.hashRef,
f_EPTF_MQTT_subscriptionDB_topicHash(v_MQTT_subscription.sessionIdx, f_unichar2charstr(vl_topicName))
);
}
v_MQTT_subscriptionDB.data[p_idx] := c_MQTT_Subscription_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_MQTT_subscriptionDB.queue);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_packetIdHash
//
// Purpose:
// Converts a pair of session ID & packet ID to the string format "session_<sessionId>:id_<packetId>" to be used as hash key
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session ID
// p_packetId - *in* *integer* - input packet ID
//
// Returns:
// charstring - converted IDs
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_packetIdHash(in integer p_sessionIdx, in integer p_packetId)
return charstring
{
return "session_"&int2str(p_sessionIdx)&":"&"id_"&int2str(p_packetId);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscriptionDB_topicHash
//
// Purpose:
// Converts a pair of session ID & topic to the string format "session_<sessionId>:topic_<topic>" to be used as hash key
//
// Parameters:
// p_sessionIdx - *in* *integer* - input session ID
// p_topic - *in* *charstring* - input topic string
//
// Returns:
// charstring - converted IDs
//
// Related Type:
// <MQTT_Subscription_DB>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscriptionDB_topicHash(in integer p_sessionIdx, in charstring p_topic)
return charstring
{
return "session_"&int2str(p_sessionIdx)&":"&"topic_"&p_topic;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_stack_fromApp
//
// Purpose:
// This is the main entry point for the MQTT stack realization of the <EPTF_MQTT_LGen_CT>
// component that handles messages received from the application layer (e.g. FSMs)
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - message that enters into the stack (will be modified by the stack)
// p_ctx - *in* <MQTT_StepCtx> - pointers for the instances related to a particular simulated entity
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_stack_fromApp(inout EPTF_MQTT_PDU p_msg, in MQTT_StepCtx p_ctx)
runs on EPTF_MQTT_LGen_CT
{
if (p_ctx.sessionIdx >=0 and p_ctx.sessionIdx < sizeof(v_MQTT_sessionDB.data) )
{
f_EPTF_MQTT_session_fromApp(p_msg, p_ctx.sessionIdx);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " sessionIdx is not valid [",p_ctx.sessionIdx,"]. Dropping message"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_stack_fromEnv
//
// Purpose:
// This is the main entry point for the MQTT stack realization of the <EPTF_MQTT_LGen_CT>
// component that handles messages received from the environment layer (e.g. transport layer)
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - message that enters into the stack (will be modified by the stack)
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_stack_fromEnv(inout EPTF_MQTT_PDU p_msg)
runs on EPTF_MQTT_LGen_CT
{
var integer vl_sIdx := f_EPTF_MQTT_sessionDB_lookUp(p_msg.transportParams.localAddress);
if (vl_sIdx >= 0)
{
// In case it's a publish response, there should be an ongoing publish transaction
if (f_EPTF_MQTT_publishResponseType(p_msg.pdu))
{
var integer vl_packetId := f_EPTF_MQTT_publishResponsePacketId(p_msg.pdu);
var integer vl_pubIdx := f_EPTF_MQTT_publishDB_lookUp(vl_sIdx, vl_packetId);
if (vl_pubIdx >= 0)
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " publish transaction found for incoming message: ", vl_pubIdx));
f_EPTF_MQTT_publish_fromEnv(p_msg, vl_pubIdx);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " no ongoing publish transaction found for incoming message (ignoring): ", p_msg));
}
}
else
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " session found for incoming message: ",vl_sIdx));
f_EPTF_MQTT_session_fromEnv(p_msg, vl_sIdx);
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " no session found for incoming message (ignoring): ", p_msg));
}
}
/*****************************************************************
@startuml EPTF_MQTT_LGen_Functions.MQTT_Session.jpg
[*] --> DISCONNECTED
DISCONNECTED --> CONNECTING: appIn: connect_msg
CONNECTING --> CONNECTED: envIn: connack_accepted
CONNECTING --> DISCONNECTED: envIn: connack_refused
CONNECTED --> DISCONNECTED: appIn: disconnect
CONNECTED --> CONNECTED: appIn: publish
CONNECTED --> CONNECTED: envIn: publish
CONNECTED --> CONNECTED: appIn: subscribe
CONNECTED --> CONNECTED: appIn: unsubscribe
CONNECTED --> CONNECTED: envIn: suback
CONNECTED --> CONNECTED: envIn: unsuback
CONNECTED --> CONNECTED: envIn: pingresp
CONNECTED --> CONNECTED: T_keepalive
@enduml
******************************************************************/
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_fromApp
//
// Purpose:
// This is the entry point for an MQTT session fsm handling events coming from the application layer (e.g. client/broker FSMs)
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - next transport message to be sent
// p_sIdx - *in* *integer* - session index
//
// Related Types:
// <MQTT_Session>
//
// FSM Diagram of a MQTT session:
// (see EPTF_MQTT_LGen_Functions.MQTT_Session.jpg)
//
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_fromApp(inout EPTF_MQTT_PDU p_msg, in integer p_sIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " session [",p_sIdx,":",v_MQTT_sessionDB.data[p_sIdx].clientId,"] current state: ",v_MQTT_sessionDB.data[p_sIdx].state));
f_EPTF_MQTT_setCtx(v_MQTT_sessionDB.data[p_sIdx].eIdx, v_MQTT_sessionDB.data[p_sIdx].fsmIdx, v_MQTT_ctx);
// State: DISCONNECTED
if (v_MQTT_sessionDB.data[p_sIdx].state == DISCONNECTED)
{
// appIn: connect
if (ischosen(p_msg.pdu.connect_msg))
{
// At this point, the local address should be filled in correctly
f_EPTF_MQTT_sessionDB_setKey(p_sIdx);
p_msg.pdu.connect_msg.payload.client_identifier.stringItem := v_MQTT_sessionDB.data[p_sIdx].clientId;
p_msg.pdu.connect_msg.payload.client_identifier.stringLength := lengthof(v_MQTT_sessionDB.data[p_sIdx].clientId);
v_MQTT_sessionDB.data[p_sIdx].keepAliveTime := int2float(p_msg.pdu.connect_msg.keep_alive-1);
f_EPTF_MQTT_session_send(p_sIdx, p_msg);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTING);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
// State: CONNECTED
else if (v_MQTT_sessionDB.data[p_sIdx].state == CONNECTED)
{
// appIn: disconnect
if (ischosen(p_msg.pdu.disconnect_msg))
{
// cancel T keepalive
f_EPTF_MQTT_session_cancelT_keepalive(p_sIdx);
f_EPTF_MQTT_session_send(p_sIdx, p_msg);
f_EPTF_MQTT_session_setState(p_sIdx, DISCONNECTED);
}
if (ischosen(p_msg.pdu.publish))
{
if (p_msg.pdu.publish.header.qos_level == AT_MOST_ONCE_DELIVERY)
{
p_msg.pdu.publish.packet_identifier := f_EPTF_MQTT_session_getNextPacketId(v_MQTT_ctx);
f_EPTF_MQTT_session_send(p_sIdx, p_msg);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
}
else if (p_msg.pdu.publish.header.qos_level == AT_LEAST_ONCE_DELIVERY)
{
p_msg.sessionIdx := p_sIdx;
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.localAddress, v_MQTT_sessionDB.data[p_sIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.remoteAddress, v_MQTT_sessionDB.data[p_sIdx].remoteAddrIdx);
p_msg.pdu.publish.packet_identifier := f_EPTF_MQTT_session_getNextPacketId(v_MQTT_ctx);
// create new Publish QoS1 Orig
var MQTT_Publish vl_publish := c_MQTT_Publish_init;
vl_publish.sessionIdx := p_sIdx;
vl_publish.side := ORIG;
vl_publish.state.qos1 := CREATED;
vl_publish.packetId := p_msg.pdu.publish.packet_identifier;
var integer vl_pubIdx := f_EPTF_MQTT_publishDB_add(vl_publish);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
// pubOut.send
f_EPTF_MQTT_publish_fromSession(p_msg, vl_pubIdx);
}
else if (p_msg.pdu.publish.header.qos_level == EXACTLY_ONE_DELIVERY)
{
p_msg.sessionIdx := p_sIdx;
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.localAddress, v_MQTT_sessionDB.data[p_sIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.remoteAddress, v_MQTT_sessionDB.data[p_sIdx].remoteAddrIdx);
p_msg.pdu.publish.packet_identifier := f_EPTF_MQTT_session_getNextPacketId(v_MQTT_ctx);
// create new Publish QoS2 Orig
var MQTT_Publish vl_publish := c_MQTT_Publish_init;
vl_publish.sessionIdx := p_sIdx;
vl_publish.side := ORIG;
vl_publish.state.qos2 := CREATED;
vl_publish.packetId := p_msg.pdu.publish.packet_identifier;
var integer vl_pubIdx := f_EPTF_MQTT_publishDB_add(vl_publish);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
// pubOut.send
f_EPTF_MQTT_publish_fromSession(p_msg, vl_pubIdx);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Publish qos level not handled. Ignoring:", p_msg));
}
}
if (ischosen(p_msg.pdu.subscribe))
{
// Fill in message
p_msg.sessionIdx := p_sIdx;
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.localAddress, v_MQTT_sessionDB.data[p_sIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.remoteAddress, v_MQTT_sessionDB.data[p_sIdx].remoteAddrIdx);
p_msg.pdu.subscribe.packet_identifier := f_EPTF_MQTT_session_getNextPacketId(v_MQTT_ctx);
// Create new Subscription
var MQTT_Subscription vl_sub := c_MQTT_Subscription_init;
vl_sub.sessionIdx := p_sIdx;
vl_sub.request := p_msg.pdu.subscribe;
vl_sub.state := UNSUBSCRIBED;
var integer vl_subIdx := f_EPTF_MQTT_subscriptionDB_add(vl_sub);
f_EPTF_MQTT_session_registerSubscription(p_sIdx, vl_subIdx);
// subscription.send
f_EPTF_MQTT_subscription_fromSession(p_msg, vl_subIdx);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
}
if (ischosen(p_msg.pdu.unsubscribe))
{
// Fill in message
p_msg.sessionIdx := p_sIdx;
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.localAddress, v_MQTT_sessionDB.data[p_sIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.remoteAddress, v_MQTT_sessionDB.data[p_sIdx].remoteAddrIdx);
p_msg.pdu.subscribe.packet_identifier := f_EPTF_MQTT_session_getNextPacketId(v_MQTT_ctx);
// Look up corresponding subscription
if (sizeof(p_msg.pdu.unsubscribe.payload[0])>0)
{
var charstring vl_topicName := f_unichar2charstr(p_msg.pdu.unsubscribe.payload[0].topic_filter);
var integer vl_subIdx := f_EPTF_MQTT_subscriptionDB_lookUp_topicName(p_sIdx, vl_topicName);
// subOut.send
if (f_EPTF_MQTT_subscriptionDB_check(vl_subIdx)) {
f_EPTF_MQTT_subscription_fromSession(p_msg, vl_subIdx);
}
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_sessionDB.data[p_sIdx].state));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_fromEnv
//
// Purpose:
// This is the entry point for an MQTT session fsm from the environment layer (e.g. transport layer)
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - transport message received
// p_sIdx - *in* *integer* - session index
//
// Related Types:
// <MQTT_Session>
//
// FSM Diagram of a MQTT session:
// (see EPTF_MQTT_LGen_Functions.MQTT_Session.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_fromEnv(inout EPTF_MQTT_PDU p_msg, in integer p_sIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " session [",v_MQTT_sessionDB.data[p_sIdx].clientId,"] current state: ",v_MQTT_sessionDB.data[p_sIdx].state));
f_EPTF_MQTT_setCtx(v_MQTT_sessionDB.data[p_sIdx].eIdx, v_MQTT_sessionDB.data[p_sIdx].fsmIdx, v_MQTT_ctx);
// State: CONNECTING
if (v_MQTT_sessionDB.data[p_sIdx].state == CONNECTING)
{
// envIn: connack
if (ischosen(p_msg.pdu.connack))
{
if (p_msg.pdu.connack.connect_return_code == 0)
{
// startT keepalive
f_EPTF_MQTT_session_startT_keepalive(p_sIdx, v_MQTT_sessionDB.data[p_sIdx].keepAliveTime);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_CONNACK_Accepted,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
else
{
f_EPTF_MQTT_session_setState(p_sIdx, DISCONNECTED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_CONNACK_Refused,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
// State: CONNECTED
else if (v_MQTT_sessionDB.data[p_sIdx].state == CONNECTED)
{
// envIn: suback
if (ischosen(p_msg.pdu.suback))
{
var integer vl_subIdx :=
f_EPTF_MQTT_subscriptionDB_lookUp_packetId(p_sIdx, p_msg.pdu.suback.packet_identifier);
f_EPTF_MQTT_subscription_fromEnv(p_msg, vl_subIdx);
}
// envIn: unsuback
else if (ischosen(p_msg.pdu.unsuback))
{
var integer vl_subIdx :=
f_EPTF_MQTT_subscriptionDB_lookUp_packetId(p_sIdx, p_msg.pdu.unsuback.packet_identifier);
f_EPTF_MQTT_subscription_fromEnv(p_msg, vl_subIdx);
}
// envIn: publish
else if (ischosen(p_msg.pdu.publish))
{
if (p_msg.pdu.publish.header.qos_level == AT_MOST_ONCE_DELIVERY)
{
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBLISH,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
else if (p_msg.pdu.publish.header.qos_level == AT_LEAST_ONCE_DELIVERY)
{
// Send PUBACK
v_MQTT_msgToSend.pdu := valueof(t_EPTF_MQTT_PUBACK(p_msg.pdu.publish.packet_identifier));
f_EPTF_MQTT_session_send(p_sIdx, v_MQTT_msgToSend);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBLISH,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
else if (p_msg.pdu.publish.header.qos_level == EXACTLY_ONE_DELIVERY)
{
// create new Publish QoS2 TERM
var MQTT_Publish vl_publish := c_MQTT_Publish_init;
vl_publish.sessionIdx := p_sIdx;
vl_publish.side := TERM;
vl_publish.state.qos2 := CREATED;
vl_publish.packetId := p_msg.pdu.publish.packet_identifier;
var integer vl_pubIdx := f_EPTF_MQTT_publishDB_add(vl_publish);
f_EPTF_MQTT_session_setState(p_sIdx, CONNECTED);
// pubOut.send
f_EPTF_MQTT_publish_fromEnv(p_msg, vl_pubIdx);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBLISH,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Publish qos level not handled. Ignoring:", p_msg));
}
}
// envIn: ping response
else if (ischosen(p_msg.pdu.pingresp))
{
if (v_MQTT_sessionDB.data[p_sIdx].reportPingResponse)
{
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PING_Response,
v_MQTT_sessionDB.data[p_sIdx].eIdx,
v_MQTT_sessionDB.data[p_sIdx].fsmIdx,
{}
);
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_sessionDB.data[p_sIdx].state));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_keepalive
//
// Purpose:
// Handles the T_keepalive timer event in the <MQTT_Session> FSM
//
// Parameters:
// pl_action - *inout* <EPTF_ScheduledAction> - the scheduled action <>
// pl_eventIndex - *in* *integer* - eveny index in the scheduler
//
// Returns:
// *boolean* - true <always>
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_keepalive(in EPTF_ScheduledAction pl_action, in integer pl_eventIndex)
runs on EPTF_MQTT_LGen_CT
return boolean
{
var integer vl_sIdx := pl_action.actionId[0];
v_MQTT_sessionDB.data[vl_sIdx].keepaliveTimer := -1;
if (v_MQTT_sessionDB.data[vl_sIdx].state == CONNECTED)
{
// Send ping request
v_MQTT_msgToSend.pdu := valueof(t_EPTF_MQTT_pingReq);
f_EPTF_MQTT_session_send(vl_sIdx, v_MQTT_msgToSend);
// startT keepAlive
f_EPTF_MQTT_session_startT_keepalive(vl_sIdx, v_MQTT_sessionDB.data[vl_sIdx].keepAliveTime);
f_EPTF_MQTT_session_setState(vl_sIdx, CONNECTED);
}
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_startT_keepalive
//
// Purpose:
// Starts the T_keepalive timer for an <MQTT_Session> FSM
//
// Parameters:
// pl_sIdx - *in* *integer* - session index (?)
// pl_time - *in* *float* - value of the keepalive timer
//
// Returns:
// *boolean* - true: succesful , false: 0 or negative timer value
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_startT_keepalive(in integer pl_sIdx, in float pl_time)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (pl_time <= 0.0) { return false; }
var boolean retval;
var EPTF_ActionId vl_actionId;
vl_actionId[0] := pl_sIdx;
retval := f_EPTF_SchedulerComp_scheduleAction(
f_EPTF_SchedulerComp_snapshotTime() + pl_time,
refers(f_EPTF_MQTT_session_keepalive),
vl_actionId,
v_MQTT_sessionDB.data[pl_sIdx].keepaliveTimer
);
return retval;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_cancelT_keepalive
//
// Purpose:
// Cancels the T_keepalive timer of an <MQTT_Session> FSM
//
// Parameters:
// pl_sessionIdx - *in* *integer* - session index
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_cancelT_keepalive(in integer pl_sessionIdx)
runs on EPTF_MQTT_LGen_CT
{
if (v_MQTT_sessionDB.data[pl_sessionIdx].keepaliveTimer >= 0)
{
if(not f_EPTF_SchedulerComp_CancelEvent(v_MQTT_sessionDB.data[pl_sessionIdx].keepaliveTimer))
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId,": could not cancel timer"));
}
v_MQTT_sessionDB.data[pl_sessionIdx].keepaliveTimer := -1;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_getNextPacketId
//
// Purpose:
// Sets the value of the packet id field in the next message to be sent in a session
//
// Parameters:
// p_ctx - *in* <MQTT_StepCtx> - Pointer of the context embedding the session id.
//
// Returns:
// *integer* - packet id for the next message
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_getNextPacketId(in MQTT_StepCtx p_ctx)
runs on EPTF_MQTT_LGen_CT
return integer
{
if (v_MQTT_sessionDB.data[p_ctx.sessionIdx].nextPacketId < 65535)
{
v_MQTT_sessionDB.data[p_ctx.sessionIdx].nextPacketId := v_MQTT_sessionDB.data[p_ctx.sessionIdx].nextPacketId + 1;
}
else
{
v_MQTT_sessionDB.data[p_ctx.sessionIdx].nextPacketId := 0;
}
return v_MQTT_sessionDB.data[p_ctx.sessionIdx].nextPacketId;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_setState
//
// Purpose:
// Sets a new state for an <MQTT_Session> FSM
//
// Parameters:
// p_sessionIdx - *in* *integer* - index of session
// p_nextState - *in* <MQTT_Session_State> - new state of the state machine
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_setState(in integer p_sessionIdx, in MQTT_Session_State p_nextState)
runs on EPTF_MQTT_LGen_CT
{
v_MQTT_sessionDB.data[p_sessionIdx].state := p_nextState;
f_EPTF_MQTT_Logging_VERBOSE(log2str("session [", p_sessionIdx,":",v_MQTT_sessionDB.data[p_sessionIdx].clientId,"] next state: ", v_MQTT_sessionDB.data[p_sessionIdx].state));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_send
//
// Purpose:
// Sends a message to the transort layer with type <EPTF_MQTT_PDU> and the provided session index
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
// p_msg - *intout* <EPTF_MQTT_PDU> - the message to be sent
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_send(in integer p_sessionIdx, inout EPTF_MQTT_PDU p_msg)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.localAddress, v_MQTT_sessionDB.data[p_sessionIdx].localAddrIdx);
f_EPTF_MQTT_addressDB_get(p_msg.transportParams.remoteAddress, v_MQTT_sessionDB.data[p_sessionIdx].remoteAddrIdx);
p_msg.transportParams.proto := {tcp := {}};
p_msg.sessionIdx := p_sessionIdx;
// envOut.send
f_EPTF_MQTT_LGen_send(p_msg);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_registerSubscription
//
// Purpose:
// Adds a subscription index to an <MQTT_Session>
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
// p_subIdx - *in* *integer* - subscription index to add
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_registerSubscription(in integer p_sessionIdx, in integer p_subIdx)
runs on EPTF_MQTT_LGen_CT
{
// Note, we don't check if it is already there
v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs[sizeof(v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs)]
:= p_subIdx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_deregisterSubscription
//
// Purpose:
// Removes a subscription index from <MQTT_Session>
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
// p_subIdx - *in* *integer* - subscription index to remove
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_deregisterSubscription(in integer p_sessionIdx, in integer p_subIdx)
runs on EPTF_MQTT_LGen_CT
{
// This is slow, it's only acceptable if the assumption that a session has only a small number
// of subscriptions
var EPTF_IntegerList vl_new := {};
for (var integer i:=0; i<sizeof(v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs); i:=i+1)
{
if (v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs[i] != p_subIdx) {
vl_new[sizeof(vl_new)] := v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs[i];
}
}
v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs := vl_new;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_registerPublish
//
// Purpose:
// Adds a publish index to an <MQTT_Session>
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
// p_subIdx - *in* *integer* - publish index to add
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_registerPublish(in integer p_sessionIdx, in integer p_pubIdx)
runs on EPTF_MQTT_LGen_CT
{
// Note, we don't check if it is already there
v_MQTT_sessionDB.data[p_sessionIdx].publishRefs[sizeof(v_MQTT_sessionDB.data[p_sessionIdx].publishRefs)]
:= p_pubIdx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_deregisterPublish
//
// Purpose:
// Removes a publish index from an <MQTT_Session>
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
// p_subIdx - *in* *integer* - publish index to add
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_deregisterPublish(in integer p_sessionIdx, in integer p_pubIdx)
runs on EPTF_MQTT_LGen_CT
{
// This is slow, it's only acceptable if the assumption that a session has only a small number
// of concurrent publish(s)
var EPTF_IntegerList vl_new := {};
for (var integer i:=0; i<sizeof(v_MQTT_sessionDB.data[p_sessionIdx].publishRefs); i:=i+1)
{
if (v_MQTT_sessionDB.data[p_sessionIdx].publishRefs[i] != p_pubIdx) {
vl_new[sizeof(vl_new)] := v_MQTT_sessionDB.data[p_sessionIdx].publishRefs[i];
}
}
v_MQTT_sessionDB.data[p_sessionIdx].publishRefs := vl_new;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_session_remove
//
// Purpose:
// Releases all resources related to an <MQTT_Session> and removes it from the <MQTT_Session_DB>
//
// Parameters:
// p_sessionIdx - *in* *integer* - session index
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_session_remove(in integer p_sessionIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_session_setState(p_sessionIdx, REMOVING);
f_EPTF_MQTT_session_cancelT_keepalive(p_sessionIdx);
// Remove subscriptions, remove publications
for (var integer i:=0; i<sizeof(v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs); i:=i+1)
{
f_EPTF_MQTT_subscription_remove(v_MQTT_sessionDB.data[p_sessionIdx].subscriptionRefs[i]);
}
// Derefer FSM pointers
f_EPTF_LGenBase_setAppDataItemOfFsmCtx(
v_MQTT_sessionDB.data[p_sessionIdx].eIdx,
v_MQTT_sessionDB.data[p_sessionIdx].fsmIdx,
v_MQTT_bIdx, c_MQTT_AppData_sessionIdx, -1
);
// Clean up DB
f_EPTF_MQTT_sessionDB_remove(p_sessionIdx);
}
/*****************************************************************
@startuml EPTF_MQTT_LGen_Functions.MQTT_Subscription.jpg
[*] --> UNSUBSCRIBED
UNSUBSCRIBED --> SUBSCRIBING: sessionIn: subscribe
SUBSCRIBED --> UNSUBSCRIBING: sessionIn: unsubscribe
SUBSCRIBING --> SUBSCRIBED: envIn: suback_accepted
SUBSCRIBING --> UNSUBSCRIBED: envIn: suback_refused
UNSUBSCRIBING --> UNSUBSCRIBED: envIn: unsuback
@enduml
******************************************************************/
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscription_fromSession
//
// Purpose:
// Implements part of the <MQTT_Subscription> FSM that handles the events coming from the <MQTT_Session>
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - message that
// p_subIdx - *in* *integer* - subscription index
//
// Related Types:
// <MQTT_Subscription>
//
// FSM Diagram of a MQTT subscription:
// (see EPTF_MQTT_LGen_Functions.MQTT_Subscription.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscription_fromSession(inout EPTF_MQTT_PDU p_msg, in integer p_subIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " subscription current state: ",v_MQTT_subscriptionDB.data[p_subIdx].state));
// State: UNSUBSCRIBED
if (v_MQTT_subscriptionDB.data[p_subIdx].state == UNSUBSCRIBED)
{
// sessionIn: subscribe
if (ischosen(p_msg.pdu.subscribe))
{
// envOut.send
f_EPTF_MQTT_LGen_send(p_msg);
f_EPTF_MQTT_subscription_setState(p_subIdx, SUBSCRIBING);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
// State: SUBSCRIBED
else if (v_MQTT_subscriptionDB.data[p_subIdx].state == SUBSCRIBED)
{
// sessionIn: unsubscribe
if (ischosen(p_msg.pdu.unsubscribe))
{
f_EPTF_MQTT_subscriptionDB_setKey_packetId(
p_subIdx, v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx, p_msg.pdu.unsubscribe.packet_identifier
);
f_EPTF_MQTT_subscription_setState(p_subIdx, UNSUBSCRIBING);
// envOut.send
f_EPTF_MQTT_LGen_send(p_msg);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_subscriptionDB.data[p_subIdx].state));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscription_fromEnv
//
// Purpose:
// Implements part of the <MQTT_Subscription> FSM that handles the events coming from the environment
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - received transport message
// p_subIdx - *in* *integer* - subscription index
//
// Related Types:
// <MQTT_Subscription>
//
// FSM Diagram of a MQTT subscription:
// (see EPTF_MQTT_LGen_Functions.MQTT_Subscription.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscription_fromEnv(inout EPTF_MQTT_PDU p_msg, in integer p_subIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " subscription current state: ",v_MQTT_subscriptionDB.data[p_subIdx].state));
// State: SUBSCRIBING
if (v_MQTT_subscriptionDB.data[p_subIdx].state == SUBSCRIBING)
{
// sessionIn: suback
if (ischosen(p_msg.pdu.suback) and sizeof(p_msg.pdu.suback.payload.return_code)>0)
{
if (p_msg.pdu.suback.payload.return_code[0] == 0)
{
f_EPTF_MQTT_subscription_setState(p_subIdx, SUBSCRIBED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_SUBACK_Accepted,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].fsmIdx,
{}
);
}
else
{
f_EPTF_MQTT_subscription_setState(p_subIdx, UNSUBSCRIBED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_SUBACK_Refused,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].fsmIdx,
{}
);
// Removing subscription
f_EPTF_MQTT_subscription_remove(p_subIdx);
}
}
// sessionIn: unsuback
if (ischosen(p_msg.pdu.unsuback))
{
f_EPTF_MQTT_subscription_setState(p_subIdx, SUBSCRIBED);
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_UNSUBACK,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx].fsmIdx,
{}
);
// Removing unsuback key
f_EPTF_MQTT_subscriptionDB_removeKey_packetId(
p_subIdx,
v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx,
p_msg.pdu.unsuback.packet_identifier
);
// Removing subscription
f_EPTF_MQTT_subscription_remove(p_subIdx);
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg));
}
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_subscriptionDB.data[p_subIdx].state));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscription_setState
//
// Purpose:
// Sets a new state of a <MQTT_Subscription> FSM
//
// Parameters:
// p_subIdx - *in* *integer* - subscription index
// p_nextState - *in* <MQTT_Subscription_State> - new state in the state machine
//
// Related Types:
// <MQTT_Subscription>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscription_setState(in integer p_subIdx, in MQTT_Subscription_State p_nextState)
runs on EPTF_MQTT_LGen_CT
{
v_MQTT_subscriptionDB.data[p_subIdx].state := p_nextState;
f_EPTF_MQTT_Logging_VERBOSE(log2str("subscription next state: ", v_MQTT_subscriptionDB.data[p_subIdx].state));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_subscription_remove
//
// Purpose:
// Removing resources related to <MQTT_Subscription> FSM
//
// Parameters:
// p_subIdx - *in* *integer* - subscription index
//
// Related Types:
// <MQTT_Subscription>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_subscription_remove(in integer p_subIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_subscription_setState(p_subIdx, REMOVING);
// Remove pointers from session
f_EPTF_MQTT_session_deregisterSubscription(v_MQTT_subscriptionDB.data[p_subIdx].sessionIdx, p_subIdx);
// Clean up DB
f_EPTF_MQTT_subscriptionDB_remove(p_subIdx);
}
/*****************************************************************
@startuml EPTF_MQTT_LGen_Functions.MQTT_Publish_qos1.jpg
[*] --> CREATED
CREATED --> PUBLISHED: sessionIn: publish
PUBLISHED --> ACKNOWLEDGED: envIn: puback
@enduml
@startuml EPTF_MQTT_LGen_Functions.MQTT_Publish_qos2.jpg
[*] --> CREATED
CREATED --> PUBLISHED: sessionIn: publish
PUBLISHED --> RELEASED: envIn: pubrec (orig)
PUBLISHED --> RECEIVED: envIn: pubrec (term)
RELEASED --> COMPLETE: envIn: pubcomp (orig)
RECEIVED --> COMPLETE: envIn: pubcomp (term)
@enduml
******************************************************************/
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_fromSession
//
// Purpose:
// Handles a publish transaction in case of QoS 1 and QoS 2 fsm requested by the application layer (e.g. client/broker FSMs)
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - transport message
// p_pubIdx - *in* *integer* - publish index
//
// Related Types:
// <MQTT_Publish>
//
// FSM Diagram of a MQTT publish:
// (see EPTF_MQTT_LGen_Functions.MQTT_Publish_qos1.jpg)
// (see EPTF_MQTT_LGen_Functions.MQTT_Publish_qos2.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_fromSession(inout EPTF_MQTT_PDU p_msg, in integer p_pubIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " publish current state: ",v_MQTT_publishDB.data[p_pubIdx].state));
// QoS 1 Originating
if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos1) and v_MQTT_publishDB.data[p_pubIdx].side == ORIG)
{
// State: CREATED
if (v_MQTT_publishDB.data[p_pubIdx].state.qos1 == CREATED)
{
// sessionIn: publish
if (ischosen(p_msg.pdu.publish))
{
// start T response watchdog
f_EPTF_MQTT_publish_startT_watchdog(p_pubIdx, tsp_EPTF_MQTT_PUBLISH_responseWatchdog);
// envOut.send
f_EPTF_MQTT_LGen_send(p_msg);
f_EPTF_MQTT_publish_setState(p_pubIdx, {qos1 := PUBLISHED});
}
else { f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg)); }
}
else {f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_publishDB.data[p_pubIdx].state.qos1)); }
}
// QoS 1 Terminating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos1) and v_MQTT_publishDB.data[p_pubIdx].side == TERM)
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " NOP"));
}
// QoS 2 Originating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos2) and v_MQTT_publishDB.data[p_pubIdx].side == ORIG)
{
// State: CREATED
if (v_MQTT_publishDB.data[p_pubIdx].state.qos2 == CREATED)
{
// sessionIn: publish
if (ischosen(p_msg.pdu.publish))
{
// start T response watchdog
f_EPTF_MQTT_publish_startT_watchdog(p_pubIdx, tsp_EPTF_MQTT_PUBLISH_responseWatchdog);
// envOut.send
f_EPTF_MQTT_LGen_send(p_msg);
f_EPTF_MQTT_publish_setState(p_pubIdx, {qos2 := PUBLISHED});
}
else { f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg)); }
}
else {f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_publishDB.data[p_pubIdx].state.qos1)); }
}
// QoS 2 Terminating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos2) and v_MQTT_publishDB.data[p_pubIdx].side == TERM)
{
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown publish type ", v_MQTT_publishDB.data[p_pubIdx]));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_fromEnv
//
// Purpose:
// Handles PUBLISH and publish response (PUB REC/PUB REL/PUB COMP) messages received from the peer (i.e. from transport layer) based on its QoS and originator
//
// Parameters:
// p_msg - *inout* <EPTF_MQTT_PDU> - received transport message
// p_pubIdx - *in* *integer* - publish index
//
// Related Types:
// <MQTT_Publish>
//
// FSM Diagram of a MQTT publish:
// (see EPTF_MQTT_LGen_Functions.MQTT_Publish_qos1.jpg)
// (see EPTF_MQTT_LGen_Functions.MQTT_Publish_qos2.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_fromEnv(inout EPTF_MQTT_PDU p_msg, in integer p_pubIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_Logging_VERBOSE(log2str(%definitionId, " publish current state: ",v_MQTT_publishDB.data[p_pubIdx].state));
// QoS 1 Originating
if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos1) and v_MQTT_publishDB.data[p_pubIdx].side == ORIG)
{
// State: PUBLISHED
if (v_MQTT_publishDB.data[p_pubIdx].state.qos1 == PUBLISHED)
{
// sessionIn: PUBACK
if (ischosen(p_msg.pdu.puback))
{
// cancel T response watchdog
f_EPTF_MQTT_publish_cancelT_watchdog(p_pubIdx);
// report event if enabled
if (v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].reportPublishResponse) {
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBACK,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].fsmIdx,
{}
);
}
// next state: ACKNOWLEDGED
f_EPTF_MQTT_publish_setState(p_pubIdx, { qos1:=ACKNOWLEDGED });
// remove publish transaction
f_EPTF_MQTT_publish_remove(p_pubIdx);
}
else { f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg)); }
}
else {f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_publishDB.data[p_pubIdx].state.qos1)); }
}
// QoS 1 Terminating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos1) and v_MQTT_publishDB.data[p_pubIdx].side == TERM)
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled, QoS1 TERM should be handled on session level: Ignoring:", p_msg));
}
// QoS 2 Originating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos2) and v_MQTT_publishDB.data[p_pubIdx].side == ORIG)
{
// State: PUBLISHED
if (v_MQTT_publishDB.data[p_pubIdx].state.qos2 == PUBLISHED)
{
// sessionIn: PUBREC
if (ischosen(p_msg.pdu.pubrec))
{
// cancel T response watchdog
f_EPTF_MQTT_publish_cancelT_watchdog(p_pubIdx);
// envOut.send PUBREL
v_MQTT_msgToSend.pdu := valueof(t_EPTF_MQTT_PUBREL(p_msg.pdu.pubrec.packet_identifier));
f_EPTF_MQTT_session_send(v_MQTT_publishDB.data[p_pubIdx].sessionIdx, v_MQTT_msgToSend);
// start publish watchdog
f_EPTF_MQTT_publish_startT_watchdog(p_pubIdx, tsp_EPTF_MQTT_PUBLISH_responseWatchdog);
// next state: RELEASED
f_EPTF_MQTT_publish_setState(p_pubIdx, { qos2:=RELEASED });
// report event if enabled
if (v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].reportPublishResponse) {
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBREC,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].fsmIdx,
{}
);
}
}
}
// State: RELEASED
else if (v_MQTT_publishDB.data[p_pubIdx].state.qos2 == RELEASED)
{
// sessionIn: PUBCOMP
if (ischosen(p_msg.pdu.pubcomp))
{
// cancel T response watchdog
f_EPTF_MQTT_publish_cancelT_watchdog(p_pubIdx);
// next state: COMPLETE
f_EPTF_MQTT_publish_setState(p_pubIdx, { qos2:=COMPLETE });
// report event if enabled
if (v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].reportPublishResponse) {
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBREC,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].fsmIdx,
{}
);
}
// remove publish transaction
f_EPTF_MQTT_publish_remove(p_pubIdx);
}
else { f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg)); }
}
else {f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_publishDB.data[p_pubIdx].state.qos2)); }
}
// QoS 2 Terminating
else if (ischosen(v_MQTT_publishDB.data[p_pubIdx].state.qos2) and v_MQTT_publishDB.data[p_pubIdx].side == TERM)
{
// State: PUBLISHED
if (v_MQTT_publishDB.data[p_pubIdx].state.qos2 == CREATED)
{
// envIn: PUBREC
if (ischosen(p_msg.pdu.publish))
{
// envOut.send PUBREC
v_MQTT_msgToSend.pdu := valueof(t_EPTF_MQTT_PUBREC(p_msg.pdu.publish.packet_identifier));
f_EPTF_MQTT_session_send(v_MQTT_publishDB.data[p_pubIdx].sessionIdx, v_MQTT_msgToSend);
// start publish watchdog
f_EPTF_MQTT_publish_startT_watchdog(p_pubIdx, tsp_EPTF_MQTT_PUBLISH_responseWatchdog);
// next state: RECEIVED
f_EPTF_MQTT_publish_setState(p_pubIdx, { qos2:=RECEIVED });
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBLISH,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].fsmIdx,
{}
);
}
}
// State: RECEIVED
else if (v_MQTT_publishDB.data[p_pubIdx].state.qos2 == RECEIVED)
{
// envIn: PUBREL
if (ischosen(p_msg.pdu.pubrel))
{
// cancel T response watchdog
f_EPTF_MQTT_publish_cancelT_watchdog(p_pubIdx);
// envOut.send PUBCOMP
v_MQTT_msgToSend.pdu := valueof(t_EPTF_MQTT_PUBCOMP(p_msg.pdu.pubrel.packet_identifier));
f_EPTF_MQTT_session_send(v_MQTT_publishDB.data[p_pubIdx].sessionIdx, v_MQTT_msgToSend);
// next state: COMPLETE
f_EPTF_MQTT_publish_setState(p_pubIdx, { qos2:=COMPLETE });
// report event if enabled
if (v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].reportPublishResponse) {
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBREL,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[p_pubIdx].sessionIdx].fsmIdx,
{}
);
}
// remove publish transaction
f_EPTF_MQTT_publish_remove(p_pubIdx);
}
else { f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " Message not handled. Ignoring:", p_msg)); }
}
else {f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown state ", v_MQTT_publishDB.data[p_pubIdx].state.qos2)); }
}
else
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId, " unknown publish type ", v_MQTT_publishDB.data[p_pubIdx]));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_watchdog
//
// Purpose:
// Handles the T_watchdog event in the <MQTT_Publish> FSM
//
// Parameters:
// pl_action - *in* <EPTF_ScheduledAction> - scheduled action
// pl_eventIndex - *in* *integer* - event index
//
// Returns:
// *boolean* - true <always>
//
// Related Types:
// <MQTT_Publish>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_watchdog(in EPTF_ScheduledAction pl_action, in integer pl_eventIndex)
runs on EPTF_MQTT_LGen_CT
return boolean
{
var integer vl_pIdx := pl_action.actionId[0];
v_MQTT_publishDB.data[vl_pIdx].watchdogTimer := -1;
f_EPTF_MQTT_dispatchEvent(
c_MQTT_eventIdx_PUBACK,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[vl_pIdx].sessionIdx].eIdx,
v_MQTT_sessionDB.data[v_MQTT_publishDB.data[vl_pIdx].sessionIdx].fsmIdx,
{}
);
f_EPTF_MQTT_publish_remove(vl_pIdx);
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_startT_watchdog
//
// Purpose:
// Start a T_watchdog timer in the <MQTT_Publish> FSM
//
// Parameters:
// pl_pIdx - *in* *integer* - publish transaction index
// pl_time - *in* *float* - time from now when the action takes place
//
// Returns:
// *boolean* - true: action scheduled , false: 0 or negative timer value is passed
//
// Related Types:
// <MQTT_Publish>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_startT_watchdog(in integer pl_pIdx, in float pl_time)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (pl_time <= 0.0) { return false; }
var boolean retval;
var EPTF_ActionId vl_actionId;
vl_actionId[0] := pl_pIdx;
retval := f_EPTF_SchedulerComp_scheduleAction(
f_EPTF_SchedulerComp_snapshotTime() + pl_time,
refers(f_EPTF_MQTT_publish_watchdog),
vl_actionId,
v_MQTT_publishDB.data[pl_pIdx].watchdogTimer //sets the event index of the next publish watchdog action
);
return retval;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_setState
//
// Purpose:
// Sets the new state of a <MQTT_Publish> FSM
//
// Parameters:
// p_pubIdx - *in* *integer* - index of the publish FSM in publishDB
// p_nextState - *in* <MQTT_Publish_State> - new state of the state machine
//
// Related Types:
// <MQTT_Publish>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_setState(in integer p_pubIdx, in MQTT_Publish_State p_nextState)
runs on EPTF_MQTT_LGen_CT
{
v_MQTT_publishDB.data[p_pubIdx].state := p_nextState;
f_EPTF_MQTT_Logging_VERBOSE(log2str("publish next state: ", v_MQTT_publishDB.data[p_pubIdx].state));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_cancelT_watchdog
//
// Purpose:
// Cancels the T_watchdog timer of an <MQTT_Publish> FSM
//
// Parameters:
// pl_publishIdx - *in* *integer* - index of the publish FSM in publishDB
//
// Related Types:
// <MQTT_Publish>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_cancelT_watchdog(in integer pl_publishIdx)
runs on EPTF_MQTT_LGen_CT
{
if (v_MQTT_publishDB.data[pl_publishIdx].watchdogTimer >= 0)
{
if(not f_EPTF_SchedulerComp_CancelEvent(v_MQTT_publishDB.data[pl_publishIdx].watchdogTimer))
{
f_EPTF_MQTT_Logging_WARNING(log2str(%definitionId,": could not cancel timer"));
}
v_MQTT_publishDB.data[pl_publishIdx].watchdogTimer := -1;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publish_remove
//
// Purpose:
// Releaseing resources of an <MQTT_Publish> FSM
//
// Parameters:
// p_pubIdx - *in* *integer* - publish index
//
// Related Types:
// <MQTT_Publish>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publish_remove(in integer p_pubIdx)
runs on EPTF_MQTT_LGen_CT
{
f_EPTF_MQTT_publish_setState(p_pubIdx, { removing := true });
// cancel timers if running
f_EPTF_MQTT_publish_cancelT_watchdog(p_pubIdx);
// Remove pointers from session
f_EPTF_MQTT_session_deregisterPublish(v_MQTT_publishDB.data[p_pubIdx].sessionIdx, p_pubIdx);
// Clean up DB
f_EPTF_MQTT_publishDB_remove(p_pubIdx);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_setStepCtx
//
// Purpose:
// Sets the entity and FSM indexes in the MQTT step context
//
// Parameters:
// pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step args
// p_ctx - *inout* <MQTT_StepCtx> - returns MQTT step context
//
// Return Type:
// *boolean* - was the operation successful?
//
// Related Function:
// <f_MQTT_step_init>
//
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_setStepCtx(in EPTF_LGenBase_TestStepArgs pl_ptr, inout MQTT_StepCtx p_ctx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (not f_EPTF_MQTT_isFsmInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, p_ctx.sessionIdx))
{
f_EPTF_MQTT_Logging_WARNING(%definitionId &
": FSM has not been initialized. The f_MQTT_step_init function must be called as first step in the FSMs using MQTT.");
return false;
}
p_ctx.eIdx := pl_ptr.eIdx;
p_ctx.fsmIdx := pl_ptr.refContext.fCtxIdx;
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_setCtx
//
// Purpose:
// Sets the instance pointers of <MQTT_StepCtx> to the related instances of a simulated device (entity) and FSM
//
// Parameters:
// p_eIdx - *in* *integer* - entity index
// p_fsmIdx - *in* *integer* - FSM index
// p_ctx - *inout* MQTT_StepCtx - returned context value
//
// Related Functions:
// <f_MQTT_step_init>
//
// Related Types:
// <MQTT_StepCtx>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_setCtx(in integer p_eIdx, in integer p_fsmIdx, inout MQTT_StepCtx p_ctx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
if (not f_EPTF_MQTT_isFsmInitialized(p_eIdx, p_fsmIdx, p_ctx.sessionIdx))
{
f_EPTF_MQTT_Logging_WARNING(%definitionId &
": FSM has not been initialized. The f_MQTT_step_init function must be called as first step in the FSMs using MQTT.");
return false;
}
p_ctx.eIdx := p_eIdx;
p_ctx.fsmIdx := p_fsmIdx;
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_isFsmInitialized
//
// Purpose:
// Checks if an FSM instance has already been initialized
//
// Parameters:
// p_eIdx - *in* *integer* - entity index
// p_fsmIdx - *in* *integer* - FSM index
// pl_sessionIdx - *inout* *integer* - returns session index if initialized, -1 if not
//
// Returns:
// boolean - true: initialized, false: not initialized
//
// Related Types:
// <MQTT_Session>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_isFsmInitialized(in integer pl_eIdx, in integer pl_fsmIdx, inout integer pl_sessionIdx)
runs on EPTF_MQTT_LGen_CT
return boolean
{
pl_sessionIdx := -1;
var EPTF_IntegerList vl_appData := f_EPTF_LGenBase_getAppDataListOfFsmCtx(pl_eIdx, pl_fsmIdx, v_MQTT_bIdx);
if (c_MQTT_AppData_sessionIdx < sizeof(vl_appData))
{
pl_sessionIdx := vl_appData[c_MQTT_AppData_sessionIdx];
}
return -1 < pl_sessionIdx and sizeof(v_MQTT_sessionDB.data) > pl_sessionIdx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_getIntValue
//
// Purpose:
// Retreives an element of an <EPTF_IntegerList> if it exists
//
// Parameters:
// pl_intList - *in* <EPTF_IntegerList> - list of integers
// pl_number - *in* *integer* - index of the integer to be retrieved
// pl_value - *inout* *integer* - returns the value of the retrieved integer
//
// Returns:
// *boolean* - true if the element exists in the integer list
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_getIntValue(
in EPTF_IntegerList pl_intList,
in integer pl_number,
inout integer pl_value)
return boolean
{
if (sizeof(pl_intList) > pl_number)
{
pl_value := pl_intList[pl_number];
return true;
}
return false;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_Logging_VERBOSE
//
// Purpose:
// Logging functions for the VERBOSE log level
//
// Parameters:
// pl_message - *in* *charstring* - string to be logged
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_Logging_VERBOSE(in @lazy charstring pl_message)
runs on EPTF_MQTT_LGen_CT
{
if (c_EPTF_Common_debugSwitch) {
f_EPTF_Logging_debugV2(pl_message, v_MQTT_loggingMaskId, {c_MQTT_LGen_Logging_DEBUGV});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_Logging_DEBUG
//
// Purpose:
// Logging functions for the DEBUG log level
//
// Parameters:
// pl_message - *in* *charstring* - string to be logged
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_Logging_DEBUG(in @lazy charstring pl_message)
runs on EPTF_MQTT_LGen_CT
{
if (c_EPTF_Common_debugSwitch) {
f_EPTF_Logging_debugV2(pl_message, v_MQTT_loggingMaskId, {c_MQTT_LGen_Logging_DEBUG});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_Logging_WARNING
//
// Purpose:
// Logging functions for the WARNING log level
//
// Parameters:
// pl_message - *in* *charstring* - string to be logged
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_Logging_WARNING(in @lazy charstring pl_message)
runs on EPTF_MQTT_LGen_CT
{
if (c_EPTF_Common_debugSwitch) {
f_EPTF_Logging_debugV2(pl_message, v_MQTT_loggingMaskId, {c_MQTT_LGen_Logging_WARNING});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_Logging_ERROR
//
// Purpose:
// Logging functions for the ERROR log level
//
// Parameters:
// pl_message - *in* *charstring* - string to be logged
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_Logging_ERROR(in @lazy charstring pl_message)
runs on EPTF_MQTT_LGen_CT
{
if (c_EPTF_Common_debugSwitch) {
f_EPTF_Logging_debugV2(pl_message, v_MQTT_loggingMaskId, {c_MQTT_LGen_Logging_ERROR});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_dispatchEvent
//
// Purpose:
// Dispatches events to an entity/fsm
//
// Parameters:
// pl_eventIdx - *in* *integer* - index of the event
// pl_eIdx - *in* *integer* - the index of the entity
// pl_fsmCtx - *in* *integer* - the index of FSM
// pl_reportedArgs - *in* <EPTF_IntegerList> - additional arguments to be reported to the entity/FSM
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_dispatchEvent(in integer pl_eventIdx, in integer pl_eIdx, in integer pl_fsmCtx, in EPTF_IntegerList pl_reportedArgs)
runs on EPTF_MQTT_LGen_CT
{
if (pl_eIdx < 0)
{
f_EPTF_LGenBase_postEvent(
{
{
v_MQTT_bIdx,
pl_eventIdx,
omit,
omit
},
pl_reportedArgs
});
}
else
{
if (pl_fsmCtx < 0)
{
f_EPTF_LGenBase_postEvent(
{
{
v_MQTT_bIdx,
pl_eventIdx,
{
pl_eIdx,
omit
}, omit
},
pl_reportedArgs
});
}
else
{
f_EPTF_LGenBase_postEvent(
{
{
v_MQTT_bIdx,
pl_eventIdx,
{
pl_eIdx,
pl_fsmCtx
}, omit
},
pl_reportedArgs
});
}
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_qos_int2enum
//
// Purpose:
// Converts the integer value of QoS to its enumerated value
//
// Parameters:
// p_qos - *in* *integer* - integer QoS value
//
// Return Type:
// <QoS> - enumerated value of the input QoS
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_qos_int2enum(in integer p_qos)
return QoS
{
if (p_qos == 0) {
return AT_MOST_ONCE_DELIVERY;
}
else if (p_qos == 1) {
return AT_LEAST_ONCE_DELIVERY;
}
else if (p_qos == 2) {
return EXACTLY_ONE_DELIVERY;
}
return RESERVED;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishResponseType
//
// Purpose:
// Checks if an MQTT message is a response to a PUBLISH
//
// Parameters:
// p_msg - *in* <MQTT_v3_1_1_ReqResp> - the MQTT message to be checked
//
// Return Type:
// *boolean* - true: message is a publish response type message
//
// Related Types:
// <EPTF_MQTT_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishResponseType(in MQTT_v3_1_1_ReqResp p_msg)
return boolean
{
return
ischosen(p_msg.puback) or
ischosen(p_msg.pubrec) or
ischosen(p_msg.pubrel) or
ischosen(p_msg.pubcomp)
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_MQTT_publishResponsePacketId
//
// Purpose:
// Get the packet identifier of an MQTT message, if it is a response to a PUBLISH
//
// Parameters:
// p_msg - *in* <MQTT_v3_1_1_ReqResp> - the input MQTT message
//
// Return Type:
// *integer* - Packet identifier value if the message was of a PUBLISH response type, -1 in other cases
///////////////////////////////////////////////////////////
function f_EPTF_MQTT_publishResponsePacketId(in MQTT_v3_1_1_ReqResp p_msg)
return integer
{
if (ischosen(p_msg.puback)) { return p_msg.puback.packet_identifier }
else if (ischosen(p_msg.pubrec)) { return p_msg.pubrec.packet_identifier }
else if (ischosen(p_msg.pubrel)) { return p_msg.pubrel.packet_identifier }
else if (ischosen(p_msg.pubcomp)) { return p_msg.pubcomp.packet_identifier }
else {
return -1;
}
}
template MQTT_v3_1_1_ReqResp t_EPTF_MQTT_pingReq :=
{
pingreq := {
header := {
flags := '0000'B
}
}
}
template MQTT_v3_1_1_ReqResp t_EPTF_MQTT_PUBACK(in integer p_packetId) :=
{
puback := {
header := {
flags := '0000'B
},
packet_identifier := p_packetId
}
}
template MQTT_v3_1_1_ReqResp t_EPTF_MQTT_PUBREL(in integer p_packetId) :=
{
pubrel := {
header := {
flags := '0010'B
},
packet_identifier := p_packetId
}
}
template MQTT_v3_1_1_ReqResp t_EPTF_MQTT_PUBREC(in integer p_packetId) :=
{
pubrec := {
header := {
flags := '0000'B
},
packet_identifier := p_packetId
}
}
template MQTT_v3_1_1_ReqResp t_EPTF_MQTT_PUBCOMP(in integer p_packetId) :=
{
pubcomp := {
header := {
flags := '0000'B
},
packet_identifier := p_packetId
}
}
}