blob: d3f66a4eaaf5d5958d65544b7490871dcfca397a [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_COAP_LGen_Functions.ttcn
// Description:
// Rev: R1A
// Prodnr: CNL 113 858
// Updated: 2020-03-04
// Contact: http://ttcn.ericsson.se
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_COAP_LGen_Functions
//
// Purpose:
// This module contains the functions of the COAP load generator component
//
// See also:
// <EPTF_COAP_LGen_Definitions>
///////////////////////////////////////////////////////////////
module EPTF_COAP_LGen_Functions
{
import from EPTF_COAP_LGen_Definitions all;
import from EPTF_COAP_Transport_Definitions all;
import from EPTF_CLL_Base_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 CoAP_Types all;
import from IPL4asp_Types all;
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_init
//
// Purpose:
// The main initialization function for the <EPTF_COAP_LGen_CT> component type
//
// Parameters:
// pl_name - *in* *charstring* - the name for the component instance
//
// Related Type:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_init(in charstring pl_name)
runs on EPTF_COAP_LGen_CT
{
if (v_COAP_initialized){return;}
f_EPTF_LGenBase_init(pl_name, 0, pl_name);
f_EPTF_Logging_init_CT(pl_name);
f_EPTF_str2int_HashMap_Init();
v_COAP_bIdx := f_EPTF_LGenBase_declareBehaviorType(
pl_name := c_COAP_behaviorType,
pl_maxCount := tsp_EPTF_COAP_LGen_maxBindableCtx,
pl_resetFn := refers(f_COAP_eCtxReset),
pl_bindFn := null,
pl_unbindFn := refers(f_COAP_eCtxUnbind),
pl_bindWithAbsIdxFn := refers(f_COAP_eCtxBind)
);
f_EPTF_COAP_LGen_initLogging();
f_EPTF_COAP_Logging_DEBUG(log2str(%definitionId,": my behavior idx is ", v_COAP_bIdx));
f_EPTF_COAP_EntityCtxDB_init();
f_EPTF_COAP_FsmCtxDB_init();
f_EPTF_COAP_transportEndpointDB_init();
f_EPTF_COAP_trDB_init();
f_EPTF_COAP_rrDB_init();
f_EPTF_COAP_templateDB_init();
f_EPTF_COAP_observedResourceDB_init();
f_EPTF_COAP_observationDB_init();
f_EPTF_COAP_blockwiseDB_init();
f_EPTF_COAP_niddDB_init();
f_EPTF_COAP_declareSteps();
f_EPTF_COAP_declareEvents();
f_EPTF_Base_registerCleanup(refers(f_COAP_cleanUp));
v_COAP_initialized := true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_initLogging
//
// Purpose:
// Initializing CLL's logging feature on the <EPTF_COAP_LGen_CT> component type
//
// Related Type:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_initLogging()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_Logging_init_CT("COAP_LGen");
v_COAP_loggingMaskId :=
f_EPTF_Logging_registerComponentMasks(
"COAP_LGen_Logging",
{"WARNING", "DEBUG", "DEBUGV", "ERROR"},
EPTF_Logging_CLL
);
if(tsp_EPTF_COAP_LGen_log_error){
f_EPTF_Logging_enableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_ERROR);
}
else {
f_EPTF_Logging_disableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_ERROR);
}
if(tsp_EPTF_COAP_LGen_log_warning){
f_EPTF_Logging_enableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_WARNING);
}
else {
f_EPTF_Logging_disableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_WARNING);
}
if(tsp_EPTF_COAP_LGen_debug){
f_EPTF_Logging_enableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_DEBUG);
}
else {
f_EPTF_Logging_disableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_DEBUG);
}
if(tsp_EPTF_COAP_LGen_debugVerbose) {
f_EPTF_Logging_enableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_DEBUGV);
}
else {
f_EPTF_Logging_disableLocalMask(v_COAP_loggingMaskId, c_COAP_LGen_Logging_DEBUGV);
}
}
///////////////////////////////////////////////////////////
// Function: f_COAP_cleanUp
//
// Purpose:
// The main clean up function for the <EPTF_COAP_LGen_CT> component type
//
// Related Type:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_COAP_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_EntityCtxDB_cleanUp();
f_EPTF_COAP_FsmCtxDB_cleanUp();
f_EPTF_COAP_transportEndpointDB_cleanUp();
f_EPTF_COAP_trDB_cleanUp();
f_EPTF_COAP_rrDB_cleanUp();
f_EPTF_COAP_templateDB_cleanUp();
f_EPTF_COAP_observedResourceDB_cleanUp();
f_EPTF_COAP_observationDB_cleanUp();
f_EPTF_COAP_blockwiseDB_cleanUp();
f_EPTF_COAP_niddDB_cleanUp();
vf_COAP_msgReceived := null;
vf_COAP_eventIndication := null;
v_COAP_initialized := false;
}
///////////////////////////////////////////////////////////
// Function: f_COAP_eCtxBind
//
// Purpose:
// This function is called by the CLL for each entity instance created on a particular instace of <EPTF_COAP_LGen_CT>
// The function will allocate and initialize an instance of <COAP_EntityCtx> in *v_COAP_EntityCtxDB* <COAP_EntityCtx_DB>
//
// 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 <COAP_EntityCtx> instance in the *v_COAP_EntityCtxDB*
//
// Related Type:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_COAP_eCtxBind(in integer pl_eIdx)
runs on EPTF_COAP_LGen_CT
return EPTF_IntegerList
{
var integer vl_eCtxIdx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_EntityCtxDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_EntityCtxDB.queue);
v_COAP_EntityCtxDB.data[vl_eCtxIdx] := c_COAP_EntityCtx_init;
v_COAP_EntityCtxDB.data[vl_eCtxIdx].eIdx := pl_eIdx;
v_COAP_EntityCtxDB.data[vl_eCtxIdx].nextToken := float2int(int2float(tsp_EPTF_COAP_maxToken)*rnd());
v_COAP_EntityCtxDB.data[vl_eCtxIdx].nextMID := float2int(int2float(65535)*rnd());
v_COAP_EntityCtxDB.data[vl_eCtxIdx].preferredOutgoingBlocksize := tsp_EPTF_COAP_BlockwiseTransfer_preferredOutgoingBlocksize;
return {vl_eCtxIdx};
}
///////////////////////////////////////////////////////////
// Function: f_COAP_eCtxUnbind
//
// Purpose:
// The reverse operation of <f_COAP_eCtxBind>. Cleans up resources reserved during <f_COAP_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_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_COAP_eCtxUnbind(in integer pl_eIdx)
runs on EPTF_COAP_LGen_CT
{
if (not v_COAP_initialized) {return;}
var integer vl_eCtxIdx:= f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_COAP_bIdx, 0);
f_EPTF_FBQ_moveFromBusyToFreeTail(vl_eCtxIdx, v_COAP_EntityCtxDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_COAP_eCtxReset
//
// Purpose:
// The resources reserved during <f_COAP_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_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_COAP_eCtxReset(in integer pl_eIdx)
runs on EPTF_COAP_LGen_CT
{
var integer vl_eCtxIdx:= f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_COAP_bIdx, 0);
v_COAP_EntityCtxDB.data[vl_eCtxIdx] := c_COAP_EntityCtx_init;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_EntityCtxDB_init
//
// Purpose:
// Initializes the *v_COAP_EntityCtxDB* <COAP_EntityCtx_DB> database
//
// Related Type:
// <COAP_EntityCtx_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_EntityCtxDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_EntityCtxDB.queue);
v_COAP_EntityCtxDB.data := {};
v_COAP_EntityCtxDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_COAP_EnityCtxDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_EntityCtxDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_EntityCtxDB* <COAP_EntityCtx_DB> database
//
// Related Type:
// <COAP_EntityCtx_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_EntityCtxDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_EntityCtxDB.queue);
v_COAP_EntityCtxDB.data :={}
f_EPTF_str2int_HashMap_Delete("EPTF_COAP_EnityCtxDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_FsmCtxDB_init
//
// Purpose:
// Initializes the *v_COAP_FsmCtxDB* <COAP_FsmCtx_DB> database
//
// Related Type:
// <COAP_FsmCtx_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_FsmCtxDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_FsmCtxDB.queue);
v_COAP_FsmCtxDB.data := {};
v_COAP_FsmCtxDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_COAP_FsmCtxDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_FsmCtxDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_FsmCtxDB* <COAP_FsmCtx_DB> database
//
// Related Type:
// <COAP_FsmCtx_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_FsmCtxDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_FsmCtxDB.queue);
v_COAP_FsmCtxDB.data :={}
f_EPTF_str2int_HashMap_Delete("EPTF_COAP_FsmCtxDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_init
//
// Purpose:
// Initializes the *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_transportEndpointDB.queue);
v_COAP_transportEndpointDB.data := {};
v_COAP_transportEndpointDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_COAP_addressDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_transportEndpointDB.queue);
v_COAP_transportEndpointDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_COAP_addressDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
//
// Parameters:
// p_te - *in* <COAP_TransportEndpoint> - the element to be added
//
// Returns:
// p_idx - *out* *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_add(in COAP_TransportEndpoint p_te, inout integer p_idx)
runs on EPTF_COAP_LGen_CT
{
p_idx := f_EPTF_COAP_transportEndpointDB_lookUp(p_te);
if (p_idx == -1)
{
p_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_transportEndpointDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_transportEndpointDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding target address ", p_idx, " ", p_te.socket, " ", p_te.proto));
f_EPTF_str2int_HashMap_Insert(v_COAP_transportEndpointDB.hashRef, f_EPTF_COAP_transportEndpointDB_Socket2String(p_te.socket), p_idx);
v_COAP_transportEndpointDB.data[p_idx] := p_te;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to retrieved
//
// Returns:
// p_te - *inout* <COAP_TransportEndpoint> - the retrieved element
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_get(inout COAP_TransportEndpoint p_te, in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_transportEndpointDB.data))
{
p_te := v_COAP_transportEndpointDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_TransportEndpoint> element in *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
// based on its socket member field
//
// Parameters:
// p_te - *in* <COAP_TransportEndpoint> - the retrieved element
//
// Returns:
// *integer* - the index of the element, or -1 if not found
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_lookUp(in COAP_TransportEndpoint p_te)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(v_COAP_transportEndpointDB.hashRef, f_EPTF_COAP_transportEndpointDB_Socket2String(p_te.socket), vl_idx);
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_transportEndpointDB_Socket2String
//
// Purpose:
// Hash function for lookups used by the *v_COAP_transportEndpointDB* <COAP_TransportEndpointDB> database
//
// Parameters:
// p_sock - *in* <Socket> - the address (of a <COAP_TransportEndpoint>)
//
// Returns:
// *charstring* - string hash unique for the <Socket> parameter
//
// Related Type:
// <COAP_TransportEndpointDB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_transportEndpointDB_Socket2String(Socket p_sock)
return charstring
{
return p_sock.hostName&":"&int2str(p_sock.portNumber);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_init
//
// Purpose:
// Initializes the *v_COAP_rrDB* <COAP_RR_DB> database
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_rrDB.queue);
v_COAP_rrDB.data := {};
v_COAP_rrDB.hashRef := f_EPTF_str2int_HashMap_New("v_COAP_rrDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_rrDB* <COAP_RR_DB> database
//
// Parameters:
// p_rr - *in* <COAP_RR> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_add(in COAP_RR p_rr)
runs on EPTF_COAP_LGen_CT
return integer
{
f_EPTF_COAP_transportEndpointDB_get(v_COAP_transportEndpoint, p_rr.addrIdx);
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_rrDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_rrDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding rr ", v_idx, " ", p_rr));
f_EPTF_str2int_HashMap_Insert(v_COAP_rrDB.hashRef, f_EPTF_COAP_rrDB_tokenHash(v_COAP_transportEndpoint.socket, p_rr.token), v_idx);
v_COAP_rrDB.data[v_idx] := p_rr;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_RR> element in *v_COAP_rrDB* <COAP_RR_DB> database
//
// Parameters:
// p_rr - *in* <Socket> - the socket (IP) address
// p_token - *in* *octetstring* - the token value
//
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_lookUp(in Socket p_sock, in octetstring p_token)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(v_COAP_rrDB.hashRef, f_EPTF_COAP_rrDB_tokenHash(p_sock, p_token), vl_idx);
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_rrDB* <COAP_RR> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_rr - *inout* <COAP_RR> - the retrieved element
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_get(in integer p_idx, inout COAP_RR p_rr)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_rrDB.data))
{
p_rr := v_COAP_rrDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_rrDB* <COAP_RR> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_transportEndpointDB_get(v_COAP_transportEndpoint, v_COAP_rrDB.data[p_idx].addrIdx);
f_EPTF_str2int_HashMap_Erase(v_COAP_rrDB.hashRef, f_EPTF_COAP_rrDB_tokenHash(v_COAP_transportEndpoint.socket, v_COAP_rrDB.data[p_idx].token));
v_COAP_rrDB.data[p_idx] := c_COAP_RR_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_rrDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_rrDB* <COAP_RR_DB> database
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_rrDB.queue);
v_COAP_rrDB.data := {};
f_EPTF_str2int_HashMap_Delete("v_COAP_rrDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rrDB_tokenHash
//
// Purpose:
// Hash function for lookups used by the *v_COAP_rrDB* <COAP_RR_DB> database
//
// Parameters:
// p_sock - *in* <Socket> - the address (of a <COAP_TransportEndpoint>)
// p_token - *in* *octetstring* - the token value
//
// Returns:
// *charstring* - string hash unique for a <COAP_RR> element
//
// Related Type:
// <COAP_RR_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rrDB_tokenHash(in Socket p_sock, in octetstring p_token)
return charstring
{
return oct2str(p_token)&":"&p_sock.hostName&":"&int2str(p_sock.portNumber);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_init
//
// Purpose:
// Initializes the *v_COAP_observationDB* <COAP_Observation_DB> database
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_observationDB.queue);
v_COAP_observationDB.data := {};
v_COAP_observationDB.hashRef := f_EPTF_str2int_HashMap_New("v_COAP_observationDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_observationDB* <COAP_Observation_DB> database
//
// Parameters:
// p_os - *in* <COAP_Observation_Server> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_add(in COAP_Observation_Server p_os)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_observationDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_observationDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding observation server ", v_idx, " ", p_os));
f_EPTF_str2int_HashMap_Insert(
v_COAP_observationDB.hashRef,
f_EPTF_COAP_observationDB_tokenHash(p_os.remoteAddress, p_os.remotePort, p_os.resourceId, p_os.observedResourceIdx), v_idx
);
v_COAP_observationDB.data[v_idx] := p_os;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_Observation_Server> element in *v_COAP_observationDB* <COAP_Observation_DB> database
//
// Parameters:
// p_remoteAddr - *in* *charstring* - the address (host) of the observer
// p_remotePort - *in* *integer* - the port of the observer
// p_resId - *in* *charstring* - the id of the observed resource
//
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_lookUp(in charstring p_remoteAddr, in integer p_remotePort, in charstring p_resId, in integer p_resIdx)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(
v_COAP_observationDB.hashRef,
f_EPTF_COAP_observationDB_tokenHash(p_remoteAddr, p_remotePort, p_resId, p_resIdx), vl_idx
);
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_observationDB* <COAP_Observation_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_os - *inout* <COAP_Observation_Server> - the retrieved element
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_get(in integer p_idx, inout COAP_Observation_Server p_os)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_observationDB.data))
{
p_os := v_COAP_observationDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_observationDB* <COAP_Observation_DB> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_str2int_HashMap_Erase(
v_COAP_observationDB.hashRef,
f_EPTF_COAP_observationDB_tokenHash(
v_COAP_observationDB.data[p_idx].remoteAddress,
v_COAP_observationDB.data[p_idx].remotePort,
v_COAP_observationDB.data[p_idx].resourceId,
v_COAP_observationDB.data[p_idx].observedResourceIdx
)
);
v_COAP_observationDB.data[p_idx] := c_COAP_Observation_Server_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_observationDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_observationDB* <COAP_Observation_DB> database
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_observationDB.queue);
v_COAP_observationDB.data := {};
f_EPTF_str2int_HashMap_Delete("v_COAP_observationDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observationDB_tokenHash
//
// Purpose:
// Hash function for lookups used by the *v_COAP_rrDB* <COAP_Observation_DB> database
//
// Parameters:
// p_remoteAddr - *in* *charstring* - the address (host) of the observer
// p_remotePort - *in* *integer* - the port of the observer
// p_resId - *in* *charstring* - the id of the observed resource
//
// Returns:
// *charstring* - string hash unique of a <COAP_Observation_Server> element
//
// Related Type:
// <COAP_Observation_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observationDB_tokenHash(in charstring p_remoteAddr, in integer p_remotePort, in charstring p_resId, in integer p_resIdx)
return charstring
{
return int2str(p_resIdx)&":"&p_remoteAddr&":"&int2str(p_remotePort)&p_resId;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_init
//
// Purpose:
// Initializes the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_blockwiseDB.queue);
v_COAP_blockwiseDB.data := {};
v_COAP_blockwiseDB.hashRef := f_EPTF_str2int_HashMap_New("v_COAP_blockwiseDB");
v_COAP_blockwiseDB.collectContent := tsp_EPTF_COAP_BlockwiseTransfer_collectContent;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Parameters:
// p_bs - *in* <COAP_Blockwise_Server> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_add(in COAP_Blockwise_Transfer p_bt)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_blockwiseDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_blockwiseDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding blockwise transfer ", v_idx, " ", p_bt));
f_EPTF_str2int_HashMap_Insert(
v_COAP_blockwiseDB.hashRef,
f_EPTF_COAP_blockwiseDB_tokenHash(p_bt.localAddress, p_bt.localPort, p_bt.resourceId), v_idx
);
v_COAP_blockwiseDB.data[v_idx] := p_bt;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_Blockwise_Transfer> element in *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Parameters:
// p_localAddr - *in* *charstring* - the address (host) of the observer
// p_localPort - *in* *integer* - the port of the observer
// p_resId - *in* *charstring* - the id of the observed resource
//
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_lookUp(in charstring p_localAddr, in integer p_localPort, in charstring p_resId)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
f_EPTF_str2int_HashMap_Find(
v_COAP_blockwiseDB.hashRef,
f_EPTF_COAP_blockwiseDB_tokenHash(p_localAddr, p_localPort, p_resId), vl_idx
);
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_bs - *inout* <COAP_Blockwise_Transfer> - the retrieved element
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_get(in integer p_idx, inout COAP_Blockwise_Transfer p_bt)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_blockwiseDB.data))
{
p_bt := v_COAP_blockwiseDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_str2int_HashMap_Erase(
v_COAP_blockwiseDB.hashRef,
f_EPTF_COAP_blockwiseDB_tokenHash(
v_COAP_blockwiseDB.data[p_idx].localAddress,
v_COAP_blockwiseDB.data[p_idx].localPort,
v_COAP_blockwiseDB.data[p_idx].resourceId
)
);
v_COAP_blockwiseDB.data[p_idx] := c_COAP_Blockwise_Transfer_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_blockwiseDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_blockwiseDB.queue);
v_COAP_blockwiseDB.data := {};
f_EPTF_str2int_HashMap_Delete("v_COAP_blockwiseDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_blockwiseDB_tokenHash
//
// Purpose:
// Hash function for lookups used by the *v_COAP_blockwiseDB* <COAP_Blockwise_DB> database
//
// Parameters:
// p_localAddr - *in* *charstring* - the address (host) of resource
// p_localPort - *in* *integer* - the port of the resource
// p_resId - *in* *charstring* - the id of the observed resource
//
// Returns:
// *charstring* - string hash unique of a <COAP_Blockwise_Server> element
//
// Related Type:
// <COAP_Blockwise_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_blockwiseDB_tokenHash(in charstring p_localAddr, in integer p_localPort, in charstring p_resId)
return charstring
{
return p_localAddr&":"&int2str(p_localPort)&p_resId;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_init
//
// Purpose:
// Initializes the *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_trDB.queue);
v_COAP_trDB.data := {};
v_COAP_trDB.hashRefOutgoing := f_EPTF_str2int_HashMap_New("v_COAP_outTrDB");
v_COAP_trDB.hashRefIncoming := f_EPTF_str2int_HashMap_New("v_COAP_incTrDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Parameters:
// p_tr - *in* <COAP_Transaction> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_add(in COAP_Transaction p_tr)
runs on EPTF_COAP_LGen_CT
return integer
{
f_EPTF_COAP_transportEndpointDB_get(v_COAP_transportEndpoint, p_tr.addrIdx);
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_trDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_trDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding tr ", v_idx, " ", p_tr));
if (p_tr.direction == OUTGOING)
{
f_EPTF_str2int_HashMap_Insert(v_COAP_trDB.hashRefOutgoing, f_EPTF_COAP_trDB_midHash(v_COAP_transportEndpoint.socket, p_tr.mid), v_idx);
}
else
{
f_EPTF_COAP_Logging_DEBUG(log2str("adding tr ", v_idx, " ", f_EPTF_COAP_trDB_midHash(v_COAP_transportEndpoint.socket, p_tr.mid)));
f_EPTF_str2int_HashMap_Insert(v_COAP_trDB.hashRefIncoming, f_EPTF_COAP_trDB_midHash(v_COAP_transportEndpoint.socket, p_tr.mid), v_idx);
}
v_COAP_trDB.data[v_idx] := p_tr;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_Transaction> element in *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Parameters:
// p_sock - *in* <Socket> - the local address of a <COAP_Transaction>
// p_mid - *in* *integer* - the message id of the <COAP_Transaction>
// p_dir - *in* <COAP_Transaction_Direction> - the direction of the <COAP_Transaction>
//
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_lookUp(in Socket p_sock, in integer p_mid, COAP_Transaction_Direction p_dir)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
if (p_dir == OUTGOING)
{
f_EPTF_str2int_HashMap_Find(v_COAP_trDB.hashRefOutgoing, f_EPTF_COAP_trDB_midHash(p_sock, p_mid), vl_idx);
}
else
{
f_EPTF_COAP_Logging_VERBOSE(log2str("look up tr ", f_EPTF_COAP_trDB_midHash(p_sock, p_mid)));
f_EPTF_str2int_HashMap_Find(v_COAP_trDB.hashRefIncoming, f_EPTF_COAP_trDB_midHash(p_sock, p_mid), vl_idx);
}
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_os - *inout* <COAP_Transaction> - the retrieved element
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_get(in integer p_idx, inout COAP_Transaction p_tr)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_trDB.data))
{
p_tr := v_COAP_trDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_trDB* <COAP_Transaction_DB> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_transportEndpointDB_get(v_COAP_transportEndpoint, v_COAP_trDB.data[p_idx].addrIdx);
if (v_COAP_trDB.data[p_idx].direction == OUTGOING)
{
f_EPTF_str2int_HashMap_Erase(v_COAP_trDB.hashRefOutgoing, f_EPTF_COAP_trDB_midHash(v_COAP_transportEndpoint.socket, v_COAP_trDB.data[p_idx].mid));
}
else
{
f_EPTF_str2int_HashMap_Erase(v_COAP_trDB.hashRefIncoming, f_EPTF_COAP_trDB_midHash(v_COAP_transportEndpoint.socket, v_COAP_trDB.data[p_idx].mid));
}
v_COAP_trDB.data[p_idx] := c_COAP_Transaction_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_trDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_trDB.queue);
v_COAP_trDB.data := {};
f_EPTF_str2int_HashMap_Delete("v_COAP_outTrDB");
f_EPTF_str2int_HashMap_Delete("v_COAP_incTrDB");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_trDB_midHash
//
// Purpose:
// Hash function for lookups used by the *v_COAP_trDB* <COAP_Transaction_DB> database
//
// Parameters:
// p_sock - *in* <Socket> - the local address of a <COAP_Transaction>
// p_mid - *in* *integer* - the message id of the <COAP_Transaction>
//
// Returns:
// *charstring* - string hash unique of a <COAP_Transaction> element
//
// Related Type:
// <COAP_Transaction_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_trDB_midHash(in Socket p_sock, in integer p_mid)
return charstring
{
return int2str(p_mid)&":"&p_sock.hostName&":"&int2str(p_sock.portNumber);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_init
//
// Purpose:
// Initializes the *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_observedResourceDB.queue);
v_COAP_observedResourceDB.data := {};
v_COAP_observedResourceDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_COAP_observedResourceDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database
//
// Parameters:
// p_or - *in* <COAP_ObservedResource> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_add(in COAP_ObservedResource p_or)
runs on EPTF_COAP_LGen_CT
return integer
{
if (f_EPTF_COAP_observedResourceDB_lookUp(p_or.localAddress, p_or.localPort, p_or.resourceId)!=-1)
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " observed resource is already added with id: ", p_or.resourceId));
return -1;
}
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_observedResourceDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_observedResourceDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding observed resource ", v_idx, " ", p_or));
f_EPTF_str2int_HashMap_Insert(
v_COAP_observedResourceDB.hashRef,
f_EPTF_COAP_observedResourceDB_tokenHash(p_or.localAddress, p_or.localPort, p_or.resourceId),
v_idx
);
v_COAP_observedResourceDB.data[v_idx] := p_or;
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " observed resource was added with id: ", p_or.resourceId, " at idx: ",v_idx));
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_lookUp
//
// Purpose:
// Gets the index of an <COAP_ObservedResource> element in *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database
//
// Parameters:
// p_localAddr - *in* *charstring* - the local address of a <COAP_ObservedResource>
// p_localPort - *in* *integer* - the local port of the <COAP_ObservedResource>
// p_resourceId - *in* *charstring* - the resource id of the <COAP_ObservedResource>
//
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_lookUp(in charstring p_localAddr, in integer p_localPort, in charstring p_resourceId)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
if (not f_EPTF_str2int_HashMap_Find(
v_COAP_observedResourceDB.hashRef,
f_EPTF_COAP_observedResourceDB_tokenHash(p_localAddr, p_localPort, p_resourceId),
vl_idx)
)
{
vl_idx := -1;
}
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_or - *inout* <COAP_ObservedResource> - the retrieved element
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_get(in integer p_idx, inout COAP_ObservedResource p_or)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_observedResourceDB.data))
{
p_or := v_COAP_observedResourceDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_str2int_HashMap_Erase(
v_COAP_observedResourceDB.hashRef,
f_EPTF_COAP_observedResourceDB_tokenHash(
v_COAP_observedResourceDB.data[p_idx].localAddress,
v_COAP_observedResourceDB.data[p_idx].localPort,
v_COAP_observedResourceDB.data[p_idx].resourceId
)
);
v_COAP_observedResourceDB.data[p_idx] := c_COAP_ObservedResource_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_observedResourceDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_observedResourceDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_observedResourceDB* <COAP_ObservedResource_DB> database
//
// Related Type:
// <COAP_ObservedResource_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_observedResourceDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_observedResourceDB.queue);
v_COAP_observedResourceDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_COAP_observedResourceDB_Hash");
}
function f_EPTF_COAP_observedResourceDB_tokenHash(in charstring p_localAddr, in integer p_localPort, in charstring p_resourceId)
return charstring
{
return p_localAddr&":"&int2str(p_localPort)&p_resourceId;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_templateDB_init
//
// Purpose:
// Initializes the *v_COAP_templateDB* <COAP_Template_DB> database by adding the templates given in <tsp_EPTF_COAP_LGen_templates>
//
// Related Type:
// <COAP_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_templateDB_init()
runs on EPTF_COAP_LGen_CT
{
v_COAP_templateDB.data := {};
v_COAP_templateDB.hashRef := f_EPTF_str2int_HashMap_New("EPTF_COAP_templateDB_Hash");
for (var integer i:=0; i<sizeof(tsp_EPTF_COAP_LGen_templates); i:=i+1) {
f_EPTF_COAP_templateDB_add(tsp_EPTF_COAP_LGen_templates[i]);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_templateDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_templateDB* <COAP_Template_DB> database
//
// Parameters:
// p_template - *in* <CoAP_Template> - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_templateDB_add(in CoAP_Template p_template)
runs on EPTF_COAP_LGen_CT
return integer
{
if (f_EPTF_COAP_templateDB_lookUp(p_template.id)!=-1)
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " template is already added with id: ", p_template.id));
return -1;
}
var integer v_idx := sizeof(v_COAP_templateDB.data);
v_COAP_templateDB.data[v_idx] := p_template;
f_EPTF_str2int_HashMap_Insert(v_COAP_templateDB.hashRef, p_template.id, v_idx);
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " template was added with id: ", p_template.id, " at idx: ",v_idx));
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_templateDB_lookUp
//
// Purpose:
// Gets the index of an <CoAP_Template> element in *v_COAP_templateDB* <COAP_Template_DB> database
//
// Parameters:
// p_id - *in* *charstring* - the id of the <CoAP_Template>
//
// Returns:
// *integer* - the index of the added element in the database, or -1 if not found
//
// Related Type:
// <COAP_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_templateDB_lookUp(in charstring p_id)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer vl_idx := -1;
if (not f_EPTF_str2int_HashMap_Find(v_COAP_templateDB.hashRef, p_id, vl_idx))
{
vl_idx := -1;
}
return vl_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_templateDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_templateDB* <COAP_Template_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_or - *inout* <CoAP_ReqResp> - the retrieved element
//
// Related Type:
// <COAP_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_templateDB_get(in integer p_idx, inout CoAP_ReqResp p_pdu)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_templateDB.data) and p_idx >= 0)
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " template is fetched with idx: ", p_idx));
p_pdu := v_COAP_templateDB.data[p_idx].msg;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_templateDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_templateDB* <COAP_Template_DB> database
//
// Related Type:
// <COAP_Template_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_templateDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
v_COAP_templateDB.data := {};
f_EPTF_str2int_HashMap_Delete("EPTF_COAP_templateDB_Hash");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_niddDB_init
//
// Purpose:
// Initializes the *v_COAP_niddDB* <COAP_NIDD_DB> database
//
// Related Type:
// <COAP_NIDD_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_niddDB_init()
runs on EPTF_COAP_LGen_CT
{
f_EPTF_FBQ_initFreeBusyQueue(v_COAP_niddDB.queue);
v_COAP_niddDB.data := {};
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_niddDB_add
//
// Purpose:
// Adds a new element to the *v_COAP_niddDB* <COAP_NIDD_DB> database
//
// Parameters:
// p_msg - *in octetstring* - the element to be added
//
// Returns:
// *integer* - the index of the added element in the database
//
// Related Type:
// <COAP_NIDD_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_niddDB_add(in octetstring p_msg)
runs on EPTF_COAP_LGen_CT
return integer
{
var integer v_idx := f_EPTF_FBQ_getOrCreateFreeSlot(v_COAP_niddDB.queue);
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_COAP_niddDB.queue);
f_EPTF_COAP_Logging_DEBUG(log2str(": "," adding nidd message at ", v_idx));
v_COAP_niddDB.data[v_idx] := p_msg;
return v_idx;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_niddDB_get
//
// Purpose:
// Retrieves an element from the *v_COAP_niddDB* <COAP_NIDD_DB> database
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be retrieved
//
// Returns:
// p_msg - *inout octetstring* - the retrieved element
//
// Related Type:
// <COAP_NIDD_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_niddDB_get(in integer p_idx, inout octetstring p_msg)
runs on EPTF_COAP_LGen_CT
{
if (p_idx < sizeof(v_COAP_niddDB.data) and p_idx >= 0)
{
p_msg := v_COAP_niddDB.data[p_idx];
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_niddDB_remove
//
// Purpose:
// Removes an element from the *v_COAP_niddDB* <COAP_NIDD_DB> database and frees up its reserved resources
//
// Parameters:
// p_idx - *in* *integer* - the index of the element to be removed
//
// Related Type:
// <COAP_NIDD_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_niddDB_remove(in integer p_idx)
runs on EPTF_COAP_LGen_CT
{
v_COAP_niddDB.data[p_idx] := ''O;
f_EPTF_FBQ_moveFromBusyToFreeTail(p_idx, v_COAP_niddDB.queue);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_niddDB_cleanUp
//
// Purpose:
// Cleans up the reserved resources of the *v_COAP_niddDB* <COAP_NIDD_DB> database
//
// Related Type:
// <COAP_NIDD_DB>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_niddDB_cleanUp()
runs on EPTF_COAP_LGen_CT
{
v_COAP_niddDB.data := {};
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_getNextMID
//
// Purpose:
// Generate the next unused message id for an entity
//
// Parameters:
// p_ctx - *in* <COAP_StepCtx> - pointers for the instances related to a particular simulated entity
//
// Returns:
// *integer* - the generated message id
//
// Related Type:
// <COAP_EntityCtx>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_getNextMID(in COAP_StepCtx p_ctx)
runs on EPTF_COAP_LGen_CT
return integer
{
if (v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextMID < 65535)
{
v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextMID := v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextMID + 1;
}
else
{
v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextMID := 0;
}
return v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextMID;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_getNextToken
//
// Purpose:
// Generate the next unused token for an entity
//
// Parameters:
// p_ctx - *in* <COAP_StepCtx> - pointers for the instances related to a particular simulated entity
//
// Returns:
// *octetstring* - the generated token identifier
//
// Related Type:
// <COAP_EntityCtx>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_getNextToken(in COAP_StepCtx p_ctx)
runs on EPTF_COAP_LGen_CT
return octetstring
{
if (v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextToken < tsp_EPTF_COAP_maxToken)
{
v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextToken := v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextToken + 1;
}
else
{
v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextToken := 0;
}
return int2oct(v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].nextToken, 4);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_send
//
// Purpose:
// The transport layer implementation <EPTF_COAP_Transport_Provider_CT> can report received <EPTF_COAP_PDU> message
// to the load generator layer <EPTF_COAP_Transport_User_CT> extended by <EPTF_COAP_LGen_CT> using this function.
//
// Parameters:
// pl_msg - *in* <EPTF_COAP_PDU> - received message
//
// Related Types:
// - <EPTF_COAP_LGen_CT>
// - <EPTF_COAP_Transport_Provider_CT>
// - <EPTF_COAP_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_send(inout EPTF_COAP_PDU pl_msg)
runs on EPTF_COAP_LGen_CT
{
// Block2 handling if payload size is greater than the preferredOutgoingBlocksize
if (f_EPTF_COAP_isResponse(pl_msg.pdu) and ispresent(pl_msg.pdu.payload))
{
//f_EPTF_COAP_Logging_DEBUG("response with payload");
var integer vl_eCtxIdx := f_EPTF_LGenBase_getBehaviorCtxItem(pl_msg.eIdx, v_COAP_bIdx, 0);
var integer v_blocksize := 16;
if (f_EPTF_COAP_getBlocksize(v_COAP_EntityCtxDB.data[vl_eCtxIdx].preferredOutgoingBlocksize, v_blocksize))
{
//f_EPTF_COAP_Logging_DEBUG(log2str("blocksize: ", v_blocksize, " payload length: ", lengthof(pl_msg.pdu.payload)));
if (lengthof(pl_msg.pdu.payload) > v_blocksize)
{
var integer v_num := 0;
var boolean v_m := true;
var integer v_szx := v_COAP_EntityCtxDB.data[v_COAP_ctx.eCtxIdx].preferredOutgoingBlocksize;
//var integer v_size2 := lengthof(pl_msg.pdu.payload);
if (f_EPTF_COAP_calculate_block2(v_num, v_m, v_szx, pl_msg.pdu.payload))
{
f_EPTF_COAP_addOption(pl_msg.pdu,
{
block2 := {
num := v_num,
m := v_m,
szx := v_szx
}
});
//f_EPTF_COAP_addOption(p_msg.pdu, { size2 := v_size2 });
}
else {
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " couldn't calculate block2 option for the notification"));
}
}
}
}
if (ischosen(pl_msg.transportParams.transport.nidd))
{
var integer vl_eCtxIdx := f_EPTF_LGenBase_getBehaviorCtxItem(pl_msg.eIdx, v_COAP_bIdx, 0);
f_CoAP_enc(CoAP_Message: {msg := pl_msg.pdu}, v_COAP_encoded);
f_EPTF_COAP_EntityCtx_addOutgoingNiddMessage(vl_eCtxIdx, v_COAP_encoded);
f_EPTF_COAP_dispatchEvent(c_COAP_eventIdx_niddMessageBuffered, pl_msg.eIdx, -1, {});
}
else
{
vf_EPTF_COAP_Transport_send.apply(pl_msg);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_receiveMessage
//
// Purpose:
// The transport layer implementation <EPTF_COAP_Transport_Provider_CT> can report received <EPTF_COAP_PDU> message
// to the load generator layer <EPTF_COAP_Transport_User_CT> extended by <EPTF_COAP_LGen_CT> using this function.
//
// Parameters:
// pl_message - *in* <EPTF_COAP_PDU> - received message
//
// Related Types:
// - <EPTF_COAP_LGen_CT>
// - <fcb_EPTF_COAP_Transport_receiveMessage>
// - <EPTF_COAP_Transport_Provider_CT>
// - <EPTF_COAP_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_receiveMessage(in EPTF_COAP_PDU pl_message)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " ", pl_message));
v_COAP_msgToProcess := pl_message;
f_EPTF_COAP_updateMessageStatistics(v_COAP_stats.incoming, v_COAP_msgToProcess);
var boolean v_duplicate := not f_EPTF_COAP_stack_fromEnv(v_COAP_msgToProcess);
if (v_duplicate) {
v_COAP_stats.noDuplicates := v_COAP_stats.noDuplicates + 1;
}
if (vf_COAP_msgReceived != null)
{
vf_COAP_msgReceived.apply(v_COAP_msgToProcess, v_duplicate, v_COAP_Stack_autoHandled);
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_receiveEvent
//
// Purpose:
// The transport layer implementation <EPTF_COAP_Transport_Provider_CT> can report received <ASP_Event> events
// to the load generator layer <EPTF_COAP_Transport_User_CT> extended by <EPTF_COAP_LGen_CT> using this function.
//
// Parameters:
// pl_message - *in* <ASP_Event> - received event
//
// Related Types:
// - <EPTF_COAP_LGen_CT>
// - <fcb_EPTF_COAP_Transport_receiveEvent>
// - <EPTF_COAP_Transport_Provider_CT>
// - <EPTF_COAP_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_receiveEvent(in ASP_Event p_event)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " ", p_event));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_LGen_transportApiResponse
//
// Purpose:
// The transport layer implementation <EPTF_COAP_Transport_Provider_CT> can report received <EPTF_COAP_Transport_Response> responses
// to the load generator layer <EPTF_COAP_Transport_User_CT> extended by <EPTF_COAP_LGen_CT> using this function.
//
// Parameters:
// pl_rsp - *in* <EPTF_COAP_Transport_Response> - received transport api response
//
// Related Types:
// - <EPTF_COAP_LGen_CT>
// - <fcb_EPTF_COAP_Transport_apiResponse>
// - <EPTF_COAP_Transport_Provider_CT>
// - <EPTF_COAP_Transport_User_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_LGen_transportApiResponse(in EPTF_COAP_Transport_Response pl_rsp)
runs on EPTF_COAP_LGen_CT
{
f_EPTF_COAP_Logging_VERBOSE(log2str("api response: ", pl_rsp));
if (ispresent(pl_rsp.params))
{
if (ischosen(pl_rsp.params.dtlsConnectionClosed)) {
}
}
if (pl_rsp.succ)
{
f_EPTF_COAP_dispatchEvent(c_COAP_eventIdx_transportSucc, pl_rsp.eIdx, pl_rsp.fsmIdx, {});
}
else
{
f_EPTF_COAP_dispatchEvent(c_COAP_eventIdx_transportFail, pl_rsp.eIdx, pl_rsp.fsmIdx, {});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_stack_fromApp
//
// Purpose:
// This is the main entry point for the COAP stack realization of the <EPTF_COAP_LGen_CT>
// component that handles messages received from the application layer (e.g. FSMs)
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the stack (will be modified by the stack)
// p_ctx - *in* <COAP_StepCtx> - pointers for the instances related to a particular simulated entity
//
// Related Types:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_stack_fromApp(inout EPTF_COAP_PDU p_msg, in COAP_StepCtx p_ctx)
runs on EPTF_COAP_LGen_CT
{
// New Req-Resp
if (v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx == -1)
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " new request response"));
var COAP_RR vl_rr := c_COAP_RR_init;
vl_rr.eIdx := p_ctx.eIdx;
vl_rr.fsmIdx := p_ctx.fsmIdx;
vl_rr.fsmCtxIdx := p_ctx.fsmCtxIdx;
vl_rr.addrIdx := v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].localAddressIdx;
vl_rr.token := f_EPTF_COAP_getNextToken(p_ctx);
vl_rr.state.client := IDLE;
p_msg.pdu.token := vl_rr.token;
var integer vl_rrIdx := f_EPTF_COAP_rrDB_add(vl_rr);
f_EPTF_COAP_rr_setState(vl_rrIdx, {client := IDLE});
v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx := vl_rrIdx;
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx);
}
// Ongoing Req-Resp
else
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " ongoing request response"));
if (f_EPTF_COAP_isRequest(p_msg.pdu))
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " replacing ongoing request response with new RR"));
var COAP_RR vl_rr := c_COAP_RR_init;
vl_rr.eIdx := p_ctx.eIdx;
vl_rr.fsmIdx := p_ctx.fsmIdx;
vl_rr.fsmCtxIdx := p_ctx.fsmCtxIdx;
vl_rr.addrIdx := v_COAP_EntityCtxDB.data[p_ctx.eCtxIdx].localAddressIdx;
vl_rr.token := f_EPTF_COAP_getNextToken(p_ctx);
vl_rr.state.client := IDLE;
p_msg.pdu.token := vl_rr.token;
var integer vl_rrIdx := f_EPTF_COAP_rrDB_add(vl_rr);
f_EPTF_COAP_rr_setState(vl_rrIdx, {client := IDLE});
v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx := vl_rrIdx;
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx);
}
else
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " handling ongoing request response with original RR"));
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_FsmCtxDB.data[p_ctx.fsmCtxIdx].rrIdx);
}
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_stack_fromEnv
//
// Purpose:
// This is the main entry point for the COAP stack realization of the <EPTF_COAP_LGen_CT>
// component that handles messages received from the environment layer (e.g. transport layer)
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the stack (will be modified by the stack)
//
// Returns:
// *boolean* - true, if the *p_msg* message was a duplicate, false if it was not
//
// Related Types:
// <EPTF_COAP_LGen_CT>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_stack_fromEnv(inout EPTF_COAP_PDU p_msg)
runs on EPTF_COAP_LGen_CT
return boolean
{
// We clear the the flag that indicates automatic handling by the stack
v_COAP_Stack_autoHandled := false;
// Answer for an ongoing tr
var integer vl_trIdx := f_EPTF_COAP_trDB_lookUp(p_msg.transportParams.localAddress, p_msg.pdu.header.message_id, OUTGOING);
if (vl_trIdx >= 0)
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " answer for ongoing tr"));
f_EPTF_COAP_tr_fromEnv(p_msg, vl_trIdx);
return true;
}
else
{
vl_trIdx := f_EPTF_COAP_trDB_lookUp(p_msg.transportParams.localAddress, p_msg.pdu.header.message_id, INCOMING);
// Deduplication. Already ongoing tr for a request
if (vl_trIdx != -1 and (p_msg.pdu.header.msg_type == CONFIRMABLE or p_msg.pdu.header.msg_type == NON_CONFIRMABLE))
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " duplicate received ", p_msg));
if (ispresent(v_COAP_trDB.data[vl_trIdx].cache))
{
f_EPTF_COAP_tr_send(v_COAP_trDB.data[vl_trIdx].cache, vl_trIdx);
}
return false;
}
// New incoming request
else
{
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " new incoming request ", p_msg));
// Create new tr
var integer vl_eCtxIdx := f_EPTF_LGenBase_getBehaviorCtxItem(p_msg.eIdx, v_COAP_bIdx, 0);
var COAP_Transaction vl_tr := c_COAP_Transaction_init;
vl_tr.mid := p_msg.pdu.header.message_id;
vl_tr.eIdx := p_msg.eIdx;
vl_tr.addrIdx := v_COAP_EntityCtxDB.data[vl_eCtxIdx].localAddressIdx;
vl_tr.state := CLOSED;
vl_tr.direction := INCOMING;
vl_tr.retransmitTimerValue := tsp_EPTF_COAP_LGen_retransmitTimerInitialValue;
vl_trIdx := f_EPTF_COAP_trDB_add(vl_tr);
f_EPTF_COAP_tr_setState(vl_trIdx, CLOSED);
f_EPTF_COAP_tr_fromEnv(v_COAP_msgToProcess, vl_trIdx);
return true;
}
}
}
/*****************************************************************
@startuml EPTF_COAP_LGen_Functions.COAP_RR_Server.jpg
[*] --> IDLE
IDLE --> SERVING: trIn: request CON
IDLE --> SEPARATE: trIn: request NON
SERVING --> REMOVING: appIn: response
SERVING --> REMOVING: appIn: empty ACK
SEPARATE --> REMOVING: appIn: response
REMOVING --> [*]
@enduml
******************************************************************/
/*****************************************************************
@startuml EPTF_COAP_LGen_Functions.COAP_RR_Client.jpg
[*] --> IDLE
IDLE --> WAITING: appIn: request
WAITING --> REMOVING: appIn: cancel
WAITING --> REMOVING: trIn: timeout
WAITING --> REMOVING: trIn: reset
WAITING --> REMOVING: trIn: response
REMOVING --> [*]
@enduml
******************************************************************/
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_handleMsg
//
// Purpose:
// This function implements a COAP request-response state machine
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the stack (will be modified by the stack)
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
//
// Related Types:
// <COAP_RR>
//
// FSM Diagram of client request-response:
// (see EPTF_COAP_LGen_Functions.COAP_RR_Client.jpg)
//
// FSM Diagram of server request-response:
// (see EPTF_COAP_LGen_Functions.COAP_RR_Server.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_handleMsg(inout EPTF_COAP_PDU p_msg, in integer p_rrIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, " rr [",v_COAP_rrDB.data[p_rrIdx].token,"] current state: ",v_COAP_rrDB.data[p_rrIdx].state));
f_EPTF_COAP_setCtx(v_COAP_rrDB.data[p_rrIdx].eIdx, v_COAP_rrDB.data[p_rrIdx].fsmIdx, v_COAP_ctx);
// RR: Client
if (ischosen(v_COAP_rrDB.data[p_rrIdx].state.client))
{
// State: IDLE
if (v_COAP_rrDB.data[p_rrIdx].state.client == IDLE)
{
// appIn: request
if (f_EPTF_COAP_isRequest(p_msg.pdu))
{
// Create new TR
var COAP_Transaction vl_tr := c_COAP_Transaction_init;
vl_tr.mid := f_EPTF_COAP_getNextMID(v_COAP_ctx);
vl_tr.eIdx := v_COAP_ctx.eIdx;
vl_tr.rrIdx := p_rrIdx;
vl_tr.addrIdx := v_COAP_EntityCtxDB.data[v_COAP_ctx.eCtxIdx].localAddressIdx;
vl_tr.state := CLOSED;
vl_tr.direction := OUTGOING;
vl_tr.retransmitTimerValue := tsp_EPTF_COAP_LGen_retransmitTimerInitialValue;
p_msg.pdu.header.message_id := vl_tr.mid;
var integer vl_trIdx := f_EPTF_COAP_trDB_add(vl_tr);
f_EPTF_COAP_tr_setState(vl_trIdx, CLOSED);
v_COAP_rrDB.data[p_rrIdx].trIdx := vl_trIdx;
// trOut.send
v_COAP_rrDB.data[p_rrIdx].request := p_msg;
f_EPTF_COAP_tr_fromRR(p_msg, v_COAP_rrDB.data[p_rrIdx].trIdx);
// next state: WAITING
f_EPTF_COAP_rr_setState(p_rrIdx, {client := WAITING});
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " only request can be handled in rr::client::IDLE. Ignoring:", p_msg));
}
}
// State: WAITING
else if (v_COAP_rrDB.data[p_rrIdx].state.client == WAITING)
{
// trIn: response
if (f_EPTF_COAP_isResponse(p_msg.pdu))
{
v_COAP_rrDB.data[p_rrIdx].response := p_msg;
// If response is CON then immediatelly answer with empty ack
if (p_msg.pdu.header.msg_type == CONFIRMABLE and
v_COAP_rrDB.data[p_rrIdx].trIdx != -1 and
ispresent(v_COAP_rrDB.data[p_rrIdx].request)
) {
var EPTF_COAP_PDU vl_empty_ack := v_COAP_rrDB.data[p_rrIdx].request;
vl_empty_ack.pdu := valueof(t_CoAP_EmptyAck);
//vl_empty_ack.pdu.token := int2oct(v_COAP_rrDB.data[p_rrIdx].token, 4);
f_EPTF_COAP_tr_fromRR(vl_empty_ack, v_COAP_rrDB.data[p_rrIdx].trIdx);
}
// report to app
f_EPTF_COAP_dispatchEventsForCode(
p_msg.pdu.header.code,
v_COAP_rrDB.data[p_rrIdx].eIdx,
v_COAP_rrDB.data[p_rrIdx].fsmIdx,
{}
);
p_msg.fsmIdx := v_COAP_rrDB.data[p_rrIdx].fsmIdx;
// finish
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," only response can be handled in rr::client::WAITING. Ignoring: ", p_msg));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," rr: unknown client state ", v_COAP_rrDB.data[p_rrIdx].state.client));
}
}
// RR: Server
else
{
// State: IDLE
if (v_COAP_rrDB.data[p_rrIdx].state.server == IDLE)
{
v_COAP_rrDB.data[p_rrIdx].remoteAddress := p_msg.transportParams.remoteAddress;
v_COAP_rrDB.data[p_rrIdx].remoteProtocol := p_msg.transportParams.transport;
v_COAP_rrDB.data[p_rrIdx].request := p_msg;
// appIn: request && CON
if (p_msg.pdu.header.msg_type == CONFIRMABLE)
{
// next state: SERVING
f_EPTF_COAP_rr_setState(p_rrIdx, {server := SERVING});
}
// appIn: request && NON
else if (p_msg.pdu.header.msg_type == NON_CONFIRMABLE)
{
// next state: SEPARATE
f_EPTF_COAP_rr_setState(p_rrIdx, {server := SEPARATE});
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " message type not handled in rr:server::IDLE ", p_msg));
}
}
// State: SEPARATE
else if (v_COAP_rrDB.data[p_rrIdx].state.server == SEPARATE)
{
// appIn: response
if (f_EPTF_COAP_isResponse(p_msg.pdu))
{
p_msg.pdu.token := v_COAP_rrDB.data[p_rrIdx].token;
f_EPTF_COAP_rr_handle_Observe_request(p_rrIdx, p_msg);
f_EPTF_COAP_rr_handle_BlockwiseTransfer_request(p_rrIdx, p_msg, v_COAP_ctx.eCtxIdx);
// create new TR
var COAP_Transaction vl_tr := c_COAP_Transaction_init;
vl_tr.mid := f_EPTF_COAP_getNextMID(v_COAP_ctx);
vl_tr.eIdx := v_COAP_ctx.eIdx;
vl_tr.rrIdx := p_rrIdx;
vl_tr.addrIdx := v_COAP_EntityCtxDB.data[v_COAP_ctx.eCtxIdx].localAddressIdx;
vl_tr.state := CLOSED;
vl_tr.direction := OUTGOING;
vl_tr.retransmitTimerValue := tsp_EPTF_COAP_LGen_retransmitTimerInitialValue;
p_msg.pdu.header.message_id := vl_tr.mid;
var integer vl_trIdx := f_EPTF_COAP_trDB_add(vl_tr);
f_EPTF_COAP_tr_setState(vl_trIdx, CLOSED);
v_COAP_rrDB.data[p_rrIdx].trIdx := vl_trIdx;
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteAddress))
{
p_msg.transportParams.remoteAddress := v_COAP_rrDB.data[p_rrIdx].remoteAddress;
}
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteProtocol))
{
p_msg.transportParams.transport := v_COAP_rrDB.data[p_rrIdx].remoteProtocol;
}
// trOut.send
v_COAP_rrDB.data[p_rrIdx].response := p_msg;
f_EPTF_COAP_tr_fromRR(p_msg, v_COAP_rrDB.data[p_rrIdx].trIdx);
// finish
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," only response can be handled in rr::server::SEPARATE. Ignoring: ", p_msg));
}
}
// State: SERVING
else if (v_COAP_rrDB.data[p_rrIdx].state.server == SERVING)
{
// appIn: response
if (f_EPTF_COAP_isResponse(p_msg.pdu) and p_msg.pdu.header.msg_type == ACKNOWLEDGEMENT)
{
// Get the TR
if (v_COAP_rrDB.data[p_rrIdx].trIdx != -1)
{
p_msg.pdu.token := v_COAP_rrDB.data[p_rrIdx].token;
f_EPTF_COAP_rr_handle_Observe_request(p_rrIdx, p_msg);
f_EPTF_COAP_rr_handle_BlockwiseTransfer_request(p_rrIdx, p_msg, v_COAP_ctx.eCtxIdx);
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteAddress))
{
p_msg.transportParams.remoteAddress := v_COAP_rrDB.data[p_rrIdx].remoteAddress;
}
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteProtocol))
{
p_msg.transportParams.transport := v_COAP_rrDB.data[p_rrIdx].remoteProtocol;
}
// trOut.send
v_COAP_rrDB.data[p_rrIdx].response := p_msg;
f_EPTF_COAP_tr_fromRR(p_msg, v_COAP_rrDB.data[p_rrIdx].trIdx);
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," couldn't find ongoing transaction in rr::server::SERVING. Ignoring: ", p_msg));
}
}
// appIn: empty ACK
else if (f_EPTF_COAP_isEmpty(p_msg.pdu) and p_msg.pdu.header.msg_type == ACKNOWLEDGEMENT)
{
// Get the TR
if (v_COAP_rrDB.data[p_rrIdx].trIdx != -1)
{
// Empty ACK has no token
//p_msg.pdu.token := int2oct(v_COAP_rrDB.data[p_rrIdx].token, 4);
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteAddress))
{
p_msg.transportParams.remoteAddress := v_COAP_rrDB.data[p_rrIdx].remoteAddress;
}
if (ispresent(v_COAP_rrDB.data[p_rrIdx].remoteProtocol))
{
p_msg.transportParams.transport := v_COAP_rrDB.data[p_rrIdx].remoteProtocol;
}
// trOut.send
f_EPTF_COAP_tr_fromRR(p_msg, v_COAP_rrDB.data[p_rrIdx].trIdx);
f_EPTF_COAP_rr_setState(p_rrIdx, {server := SEPARATE});
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," couldn't find ongoing transaction in rr::server::SERVING. Ignoring: ", p_msg));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId," response must be an ACK, message cannot be handled in rr::server::SERVING. Ignoring: ", p_msg));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, "unknown server state ", v_COAP_rrDB.data[p_rrIdx].state.server));
}
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_reset
//
// Purpose:
// This function handles the *reset* event of a <COAP_RR> state machine
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_reset(in integer p_rrIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
// RR: Client
if (ischosen(v_COAP_rrDB.data[p_rrIdx].state.client))
{
// State: WAITING
if (v_COAP_rrDB.data[p_rrIdx].state.client == WAITING)
{
f_EPTF_COAP_dispatchEvent(
c_COAP_eventIdx_trRST,
v_COAP_rrDB.data[p_rrIdx].eIdx,
v_COAP_rrDB.data[p_rrIdx].fsmIdx,
{}
);
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " reset only handled rr:client::WAITING"));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " reset not handled in rr:server"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_timeout
//
// Purpose:
// This function handles the *timeout* event of a <COAP_RR> state machine
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_timeout(in integer p_rrIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
// RR: Client
if (ischosen(v_COAP_rrDB.data[p_rrIdx].state.client))
{
// State: WAITING
if (v_COAP_rrDB.data[p_rrIdx].state.client == WAITING)
{
v_COAP_stats.noTransactionTimeouts := v_COAP_stats.noTransactionTimeouts + 1;
f_EPTF_COAP_dispatchEvent(
c_COAP_eventIdx_trTimeout,
v_COAP_rrDB.data[p_rrIdx].eIdx,
v_COAP_rrDB.data[p_rrIdx].fsmIdx,
{}
);
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " reset only handled rr:client::WAITING"));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " reset not handled in rr:server"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_cancel
//
// Purpose:
// This function handles the *cancel* event of a <COAP_RR> state machine
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_cancel(in integer p_rrIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
// RR: Client
if (ischosen(v_COAP_rrDB.data[p_rrIdx].state.client))
{
// State: WAITING
if (v_COAP_rrDB.data[p_rrIdx].state.client == WAITING)
{
if (v_COAP_rrDB.data[p_rrIdx].trIdx != -1)
{
f_EPTF_COAP_tr_cancel(v_COAP_rrDB.data[p_rrIdx].trIdx);
f_EPTF_COAP_rr_remove(p_rrIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " there is no ongoing transaction to handle cancel"));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " cancel only handled rr:client::WAITING"));
}
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " cance; not handled in rr:server"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_remove
//
// Purpose:
// This function handles the removal and clean up of a <COAP_RR> state machine instance from the DB
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB>
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_remove(in integer p_rrIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
if (ischosen(v_COAP_rrDB.data[p_rrIdx].state.client))
{
f_EPTF_COAP_rr_setState(p_rrIdx, {client := REMOVING});
}
else
{
f_EPTF_COAP_rr_setState(p_rrIdx, {server := REMOVING});
}
//action(%definitionId, " rr: (rrIdx: ",p_rrIdx,") ",v_COAP_rrDB.data[p_rrIdx]);
if (v_COAP_rrDB.data[p_rrIdx].trIdx != -1)
{
if (v_COAP_trDB.data[v_COAP_rrDB.data[p_rrIdx].trIdx].rrIdx == p_rrIdx)
{
v_COAP_trDB.data[v_COAP_rrDB.data[p_rrIdx].trIdx].rrIdx := -1;
}
}
if (v_COAP_rrDB.data[p_rrIdx].fsmCtxIdx != -1)
{
//action(%definitionId, " fsm: ",v_COAP_FsmCtxDB.data[v_COAP_rrDB.data[p_rrIdx].fsmCtxIdx]);
if (v_COAP_FsmCtxDB.data[v_COAP_rrDB.data[p_rrIdx].fsmCtxIdx].rrIdx == p_rrIdx)
{
v_COAP_FsmCtxDB.data[v_COAP_rrDB.data[p_rrIdx].fsmCtxIdx].rrIdx := -1;
}
}
f_EPTF_COAP_rrDB_remove(p_rrIdx);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_setState
//
// Purpose:
// This function sets the current state of a <COAP_RR> state machine instance
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
// p_nextState - *in* <COAP_RR_State> - next state of the state machine
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_setState(in integer p_rrIdx, in COAP_RR_State p_nextState)
runs on EPTF_COAP_LGen_CT
{
if (p_rrIdx < 0 or p_rrIdx >= sizeof(v_COAP_rrDB.data)) { return }
v_COAP_rrDB.data[p_rrIdx].state := p_nextState;
f_EPTF_COAP_Logging_VERBOSE(log2str("rr [", v_COAP_rrDB.data[p_rrIdx].token,"] next state: ", v_COAP_rrDB.data[p_rrIdx].state));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_handle_Observe_request
//
// Purpose:
// This function handles an incoming Observe request as part of a <COAP_RR> state machine instance
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
// p_msg - *in* <EPTF_COAP_PDU> - incoming message
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_handle_Observe_request(in integer p_rrIdx, inout EPTF_COAP_PDU p_msg)
runs on EPTF_COAP_LGen_CT
{
// In case it's a response to an Observe request
var integer v_observeOptionIdx := f_EPTF_COAP_hasObserve(v_COAP_rrDB.data[p_rrIdx].request.pdu);
if (v_observeOptionIdx >= 0)
{
// In case the request was an observe subscribe
if (v_COAP_rrDB.data[p_rrIdx].request.pdu.options[v_observeOptionIdx].observe == 0)
{
// In case it is a positive (2xx) response
if (p_msg.pdu.header.code.class == 2)
{
// We are adding the observation to the DB
f_EPTF_COAP_EntityCtx_addObservation(v_COAP_ctx.eCtxIdx, v_COAP_rrDB.data[p_rrIdx].request);
f_EPTF_COAP_addOption(p_msg.pdu, { observe := c_COAP_Observation_initSeqNum });
}
}
// In case the request was an observe unsubscribe
else if (v_COAP_rrDB.data[p_rrIdx].request.pdu.options[v_observeOptionIdx].observe == 1)
{
// Let's fetch the uri path
var charstring vl_resourceId := f_EPTF_COAP_uriPathToString(v_COAP_rrDB.data[p_rrIdx].request.pdu);
f_EPTF_COAP_Logging_DEBUG(log2str("observe unsubscribe for ", vl_resourceId));
// Let's try to look up the observed resource
var integer vl_observedResourceIdx := f_EPTF_COAP_observedResourceDB_lookUp(
v_COAP_rrDB.data[p_rrIdx].request.transportParams.localAddress.hostName,
v_COAP_rrDB.data[p_rrIdx].request.transportParams.localAddress.portNumber,
vl_resourceId
);
f_EPTF_COAP_Logging_DEBUG(log2str("observedResourceIdx: ", vl_observedResourceIdx));
if (vl_observedResourceIdx != -1)
{
// Let's try to look up the observation server
var integer vl_observationIdx := f_EPTF_COAP_observationDB_lookUp(
v_COAP_rrDB.data[p_rrIdx].request.transportParams.remoteAddress.hostName,
v_COAP_rrDB.data[p_rrIdx].request.transportParams.remoteAddress.portNumber,
vl_resourceId,
vl_observedResourceIdx
);
f_EPTF_COAP_Logging_DEBUG(log2str("observationIdx: ", vl_observationIdx));
if (vl_observationIdx != -1)
{
f_EPTF_COAP_ObservationServer_cancelReceivedFromEnv(vl_observationIdx);
}
}
}
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_rr_handle_BlockwiseTransfer_request
//
// Purpose:
// This function handles an incoming blockwise transfer request as part of a <COAP_RR> state machine instance
//
// Parameters:
// p_rrIdx - *in* *integer* - index of the <COAP_RR> in the <COAP_RR_DB> that will handle the message
// p_msg - *in* <EPTF_COAP_PDU> - incoming message
// p_eCtxIdx - *in* *integer* - entity context index
//
// Related Types:
// <COAP_RR>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_rr_handle_BlockwiseTransfer_request(in integer p_rrIdx, inout EPTF_COAP_PDU p_msg, in integer p_eCtxIdx)
runs on EPTF_COAP_LGen_CT
{
// In case it's a response to a Block1 request
var integer v_block1OptionIdx := f_EPTF_COAP_hasBlock1(v_COAP_rrDB.data[p_rrIdx].request.pdu);
if (v_block1OptionIdx >= 0)
{
f_EPTF_COAP_rr_handle_Block1Transfer_request(p_rrIdx, p_msg, p_eCtxIdx, v_block1OptionIdx);
}
// In case it's a response to a Block2 request
var integer v_block2OptionIdx := f_EPTF_COAP_hasBlock2(v_COAP_rrDB.data[p_rrIdx].request.pdu);
if (v_block2OptionIdx >= 0)
{
f_EPTF_COAP_rr_handle_Block2Transfer_request(p_rrIdx, p_msg, p_eCtxIdx, v_block2OptionIdx);
}
}
function f_EPTF_COAP_rr_handle_Block1Transfer_request(in integer p_rrIdx, inout EPTF_COAP_PDU p_msg, in integer p_eCtxIdx, in integer p_block1OptionIdx)
runs on EPTF_COAP_LGen_CT
{
// In case it is a positive (2xx) response
if (p_msg.pdu.header.code.class == 2)
{
// 204 response -> stateless block1 server
if (p_msg.pdu.header.code.detail == 4)
{
f_EPTF_COAP_addOption(p_msg.pdu,
{
block1 := {
num := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.num,
m := false,
szx := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.szx
}
});
}
// 231 response -> atomic server creation
else if (p_msg.pdu.header.code.detail == 31)
{
// if it is an initial block we can add an atomic server
if (v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.num == 0)
{
f_EPTF_COAP_EntityCtx_addBlockwiseTransfer(
v_COAP_ctx.eIdx, v_COAP_ctx.fsmIdx, v_COAP_ctx.eCtxIdx,
p_block1OptionIdx, v_COAP_rrDB.data[p_rrIdx].request);
// If we have a smaller preferred block size, we send that back
if (
ispresent(v_COAP_EntityCtxDB.data[p_eCtxIdx].preferredBlocksize) and
v_COAP_EntityCtxDB.data[p_eCtxIdx].preferredBlocksize < v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.szx
)
{
f_EPTF_COAP_addOption(p_msg.pdu,
{
block1 := {
num := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.num,
m := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.m,
szx := v_COAP_EntityCtxDB.data[p_eCtxIdx].preferredBlocksize
}
});
}
else
{
f_EPTF_COAP_addOption(p_msg.pdu,
{
block1 := {
num := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.num,
m := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.m,
szx := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.szx
}
});
}
}
// not an initial block
else
{
f_EPTF_COAP_addOption(p_msg.pdu,
{
block1 := {
num := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.num,
m := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.m,
szx := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block1OptionIdx].block1.szx
}
});
}
}
}
}
function f_EPTF_COAP_rr_handle_Block2Transfer_request(in integer p_rrIdx, inout EPTF_COAP_PDU p_msg, in integer p_eCtxIdx, in integer p_block2OptionIdx)
runs on EPTF_COAP_LGen_CT
{
// In case it is a positive (2xx) response and we have a payload
if (p_msg.pdu.header.code.class == 2 and ispresent(p_msg.pdu.payload))
{
var integer v_num := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block2OptionIdx].block2.num;
var boolean v_m := false;
var integer v_szx := v_COAP_rrDB.data[p_rrIdx].request.pdu.options[p_block2OptionIdx].block2.szx;
//var integer v_size2 := lengthof(p_msg.pdu.payload);
if (f_EPTF_COAP_calculate_block2(v_num, v_m, v_szx, p_msg.pdu.payload))
{
f_EPTF_COAP_addOption(p_msg.pdu,
{
block2 := {
num := v_num,
m := v_m,
szx := v_szx
}
});
//f_EPTF_COAP_addOption(p_msg.pdu, { size2 := v_size2 });
}
else
{
// Inalid block requested
// Send back 4xx message
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " invalid block requested, sending back 404"));
p_msg.pdu.payload := omit;
p_msg.pdu.header.code.class := 4;
p_msg.pdu.header.code.detail := 4;
}
}
}
function f_EPTF_COAP_calculate_block2(inout integer p_num, inout boolean p_m, inout integer p_szx, inout octetstring p_payload)
runs on EPTF_COAP_LGen_CT
return boolean
{
var integer v_blocksize := 16;
// Get blocksize
if (f_EPTF_COAP_getBlocksize(p_szx, v_blocksize))
{
// Calculate the number of the blocks needed for the payload:
var integer v_payloadLength := lengthof(p_payload);
var integer v_payloadBlockNum := v_payloadLength/v_blocksize;
if (v_payloadLength mod v_blocksize > 0) { v_payloadBlockNum := v_payloadBlockNum + 1}
//f_EPTF_COAP_Logging_DEBUG(log2str("num: ", p_num, " payloadBlockNum: ", v_payloadBlockNum));
// Check if p_num is a valid block
if (p_num < v_payloadBlockNum)
{
// Calculate block starting and ending octet indices
var integer v_blockStartOctIdx := p_num * v_blocksize;
var integer v_blockEndOctIdx := (p_num+1) * v_blocksize - 1;
if (v_blockEndOctIdx >= v_payloadLength) { v_blockEndOctIdx := v_payloadLength-1}
//f_EPTF_COAP_Logging_DEBUG(log2str("v_blockStartOctIdx: ", v_blockStartOctIdx));
// Truncate the payload
p_payload := substr(p_payload, v_blockStartOctIdx, (v_blockEndOctIdx-v_blockStartOctIdx+1));
//f_EPTF_COAP_Logging_DEBUG(log2str("payload: ", p_payload));
// Calculate the More flag
if (p_num < v_payloadBlockNum - 1) { p_m := true; }
else if (p_num == v_payloadBlockNum - 1) { p_m := false; }
return true;
}
else {
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " p_num is no a valid block p_num: ", p_num, " v_payloadBlockNum: ", v_payloadBlockNum));
return false;
}
}
else {
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " blocksie is not valid p_szx: ", p_szx));
return false;
}
return false;
}
function f_EPTF_COAP_getBlocksize(in integer p_szx, inout integer p_blocksize)
return boolean
{
if (p_szx == 0) { p_blocksize := 16; return true; }
else if (p_szx == 1) { p_blocksize := 32; return true; }
else if (p_szx == 2) { p_blocksize := 64; return true; }
else if (p_szx == 3) { p_blocksize := 128; return true; }
else if (p_szx == 4) { p_blocksize := 256; return true; }
else if (p_szx == 5) { p_blocksize := 512; return true; }
else if (p_szx == 6) { p_blocksize := 1024; return true; }
return false;
}
/*****************************************************************
@startuml EPTF_COAP_LGen_Functions.COAP_Transaction.jpg
[*] --> CLOSED
CLOSED --> CLOSED: envIn: NON
CLOSED --> CLOSED: rrIn: NON
CLOSED --> CLOSED: envIn: RST
CLOSED --> REMOVING: T_lifetime
CLOSED --> REMOVING: rrIn: ACK
CLOSED --> RELIABLE_TX: rrIn: CON
RELIABLE_TX --> CLOSED: envIn: ACK
RELIABLE_TX --> CLOSED: envIn: RST
RELIABLE_TX --> CLOSED: rrIn: CANCEL
RELIABLE_TX --> RELIABLE_TX: T_retransmit
RELIABLE_TX --> REMOVING: T_lifetime
ACK_PENDING --> CLOSED: rrIn: ACK
ACK_PENDING --> CLOSED: rrIn: RST
ACK_PENDING --> REMOVING: T_lifetime
REMOVING --> [*]
@enduml
******************************************************************/
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_fromRR
//
// Purpose:
// This function implements a COAP request-response state machine by handling the incoming message from a <COAP_RR>
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the transaction (will be modified by the stack)
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> instance in the <COAP_Transaction_DB> that will handle the message
//
// Related Types:
// <COAP_Transaction>
//
// FSM Diagram of a COAP transaction:
// (see EPTF_COAP_LGen_Functions.COAP_Transaction.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_fromRR(inout EPTF_COAP_PDU p_msg, in integer p_trIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_trIdx < 0 or p_trIdx >= sizeof(v_COAP_trDB.data)) { return }
f_EPTF_COAP_Logging_DEBUG(log2str("current state: ", v_COAP_trDB.data[p_trIdx].state));
// State: CLOSED
if (v_COAP_trDB.data[p_trIdx].state == CLOSED)
{
// rrIn: CON
if (p_msg.pdu.header.msg_type == CONFIRMABLE)
{
f_EPTF_COAP_tr_startT_retransmit(p_trIdx);
// start EXCHANGE_LIFETIME
f_EPTF_COAP_tr_startT_lifetime(p_trIdx, tsp_EPTF_COAP_EXCHANGE_LIFETIME);
f_EPTF_COAP_tr_startT_rtt(p_trIdx);
// send to env
f_EPTF_COAP_tr_send(p_msg, p_trIdx);
// next state: RELIABLE_TX
f_EPTF_COAP_tr_setState(p_trIdx, RELIABLE_TX);
}
// rrIn: NON
else if (p_msg.pdu.header.msg_type == NON_CONFIRMABLE)
{
// start EXCHANGE_LIFETIME
f_EPTF_COAP_tr_startT_lifetime(p_trIdx, tsp_EPTF_COAP_EXCHANGE_LIFETIME);
// out.send
f_EPTF_COAP_tr_send(p_msg, p_trIdx);
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
// OLD: finish f_EPTF_COAP_tr_remove(p_trIdx);
}
// rrIn: ACK
else if (p_msg.pdu.header.msg_type == ACKNOWLEDGEMENT)
{
// out.send
f_EPTF_COAP_tr_send(p_msg, p_trIdx);
// finish
f_EPTF_COAP_tr_remove(p_trIdx);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, "cannot handle msg type ",p_msg.pdu.header.msg_type," in state ",v_COAP_trDB.data[p_trIdx].state));
}
}
// State: ACK_PENDING
else if (v_COAP_trDB.data[p_trIdx].state == ACK_PENDING)
{
// rrIn: ACK
if (p_msg.pdu.header.msg_type == ACKNOWLEDGEMENT)
{
p_msg.pdu.header.message_id := v_COAP_trDB.data[p_trIdx].mid;
// store in cache
v_COAP_trDB.data[p_trIdx].cache := p_msg;
// out.send
f_EPTF_COAP_tr_send(p_msg, p_trIdx);
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
// rrIn: RST
else if (p_msg.pdu.header.msg_type == RESET)
{
p_msg.pdu.header.message_id := v_COAP_trDB.data[p_trIdx].mid;
// store in cache
v_COAP_trDB.data[p_trIdx].cache := p_msg;
// out.send
f_EPTF_COAP_tr_send(p_msg, p_trIdx);
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, "cannot handle msg type ",p_msg.pdu.header.msg_type," in state ",v_COAP_trDB.data[p_trIdx].state));
}
}
else
{
f_EPTF_COAP_Logging_ERROR(log2str(%definitionId, "unknown state ", p_msg));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_fromEnv
//
// Purpose:
// This function implements a COAP request-response state machine by handling the incoming message from a <COAP_RR>
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the transaction (will be modified by the stack)
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> instance in the <COAP_Transaction_DB> that will handle the message
//
// Related Types:
// <COAP_Transaction>
//
// FSM Diagram of a COAP transaction:
// (see EPTF_COAP_LGen_Functions.COAP_Transaction.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_fromEnv(inout EPTF_COAP_PDU p_msg, in integer p_trIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_trIdx < 0 or p_trIdx >= sizeof(v_COAP_trDB.data)) { return }
f_EPTF_COAP_Logging_VERBOSE(log2str(%definitionId, "current state: ", v_COAP_trDB.data[p_trIdx].state));
// State: CLOSED
if (v_COAP_trDB.data[p_trIdx].state == CLOSED)
{
// envIn: NON
if (p_msg.pdu.header.msg_type == NON_CONFIRMABLE)
{
// start NON_LIFETIME
f_EPTF_COAP_tr_startT_lifetime(p_trIdx, tsp_EPTF_COAP_NON_LIFETIME);
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
// rrOut.send
if (v_COAP_trDB.data[p_trIdx].rrIdx == -1)
{
var integer vl_rrIdx := f_EPTF_COAP_rrDB_lookUp(p_msg.transportParams.localAddress, p_msg.pdu.token);
if (vl_rrIdx >= 0)
{
v_COAP_trDB.data[p_trIdx].rrIdx := vl_rrIdx;
v_COAP_rrDB.data[vl_rrIdx].trIdx := p_trIdx;
f_EPTF_COAP_rr_handleMsg(p_msg, vl_rrIdx);
}
else
{
f_EPTF_COAP_dispatchEventForObserve_ifExists(p_msg.pdu, p_msg.eIdx, -1);
if (not f_EPTF_COAP_tr_handleBlockwiseTransfer(p_trIdx, p_msg))
{
f_EPTF_COAP_dispatchEventsForCode(
p_msg.pdu.header.code,
p_msg.eIdx,
-1,
{}
);
}
}
}
else
{
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_trDB.data[p_trIdx].rrIdx);
}
}
// envIn: CON
else if (p_msg.pdu.header.msg_type == CONFIRMABLE)
{
// start EXCHANGE_LIFETIME
f_EPTF_COAP_tr_startT_lifetime(p_trIdx, tsp_EPTF_COAP_EXCHANGE_LIFETIME);
// next state: ACK_PENDING
f_EPTF_COAP_tr_setState(p_trIdx, ACK_PENDING);
// rrOut.send
if (v_COAP_trDB.data[p_trIdx].rrIdx == -1)
{
var integer vl_rrIdx := f_EPTF_COAP_rrDB_lookUp(p_msg.transportParams.localAddress, p_msg.pdu.token);
if (vl_rrIdx >= 0)
{
v_COAP_trDB.data[p_trIdx].rrIdx := vl_rrIdx;
v_COAP_rrDB.data[vl_rrIdx].trIdx := p_trIdx;
f_EPTF_COAP_rr_handleMsg(p_msg, vl_rrIdx);
}
else
{
f_EPTF_COAP_dispatchEventForObserve_ifExists(p_msg.pdu, p_msg.eIdx, -1);
if (not f_EPTF_COAP_tr_handleBlockwiseTransfer(p_trIdx, p_msg))
{
f_EPTF_COAP_dispatchEventsForCode(
p_msg.pdu.header.code,
p_msg.eIdx,
-1,
{}
);
}
}
}
else
{
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_trDB.data[p_trIdx].rrIdx);
}
}
// envIn: RST
else if (p_msg.pdu.header.msg_type == RESET)
{
// report reset
if (v_COAP_trDB.data[p_trIdx].rrIdx != -1) {
f_EPTF_COAP_rr_reset(v_COAP_trDB.data[p_trIdx].rrIdx);
}
// report observe cancel
if (v_COAP_trDB.data[p_trIdx].obsIdx != -1) {
f_EPTF_COAP_ObservationServer_cancelReceivedFromEnv(v_COAP_trDB.data[p_trIdx].obsIdx);
}
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, "cannot handle msg type ",p_msg.pdu.header.msg_type," in state ",v_COAP_trDB.data[p_trIdx].state));
}
}
// State: RELIABLE_TX
else if (v_COAP_trDB.data[p_trIdx].state == RELIABLE_TX)
{
if (p_msg.pdu.header.msg_type == ACKNOWLEDGEMENT)
{
// cancel T retransmission
f_EPTF_COAP_tr_cancelT_retransmit(p_trIdx);
f_EPTF_COAP_tr_stopT_rtt(p_trIdx);
if (not f_EPTF_COAP_isEmpty(p_msg.pdu) and v_COAP_trDB.data[p_trIdx].rrIdx != -1)
{
f_EPTF_COAP_rr_handleMsg(p_msg, v_COAP_trDB.data[p_trIdx].rrIdx);
}
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
else if (p_msg.pdu.header.msg_type == RESET)
{
// cancel T retransmission
f_EPTF_COAP_tr_cancelT_retransmit(p_trIdx);
// report reset
if (v_COAP_trDB.data[p_trIdx].rrIdx != -1) {
f_EPTF_COAP_rr_reset(v_COAP_trDB.data[p_trIdx].rrIdx);
}
// report observe cancel
if (v_COAP_trDB.data[p_trIdx].obsIdx != -1) {
f_EPTF_COAP_ObservationServer_cancelReceivedFromEnv(v_COAP_trDB.data[p_trIdx].obsIdx);
}
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, "cannot handle msg type ",p_msg.pdu.header.msg_type," in state ",v_COAP_trDB.data[p_trIdx].state));
}
}
else if (v_COAP_trDB.data[p_trIdx].state == ACK_PENDING)
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " messages from environment in ACK_PENDING are not expected"));
}
else
{
f_EPTF_COAP_Logging_ERROR(log2str(%definitionId, " unknown state"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_handleBlockwiseTransfer
//
// Purpose:
// This function handles incoming COAP messages in case they are blockwise transfer related.
//
// Parameters:
// p_msg - *inout* <EPTF_COAP_PDU> - message that enters into the transaction
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> instance in the <COAP_Transaction_DB> that will handle the message
//
// Returns:
// *boolean* - true if the message is blockwise transfer related
//
// Related Types:
// <COAP_Transaction>
//
// FSM Diagram of a COAP transaction:
// (see EPTF_COAP_LGen_Functions.COAP_Transaction.jpg)
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_handleBlockwiseTransfer(in integer p_trIdx, inout EPTF_COAP_PDU p_msg)
runs on EPTF_COAP_LGen_CT
return boolean
{
var integer v_block1OptionIdx := f_EPTF_COAP_hasBlock1(p_msg.pdu);
// If we have a block1 option
if (v_block1OptionIdx >= 0)
{
v_COAP_stats.block1.noBlocks := v_COAP_stats.block1.noBlocks + 1;
var charstring v_uriPath := f_EPTF_COAP_uriPathToString(p_msg.pdu);
var integer v_blockwiseIdx := f_EPTF_COAP_blockwiseDB_lookUp(
p_msg.transportParams.localAddress.hostName,
p_msg.transportParams.localAddress.portNumber,
v_uriPath
);
// If we have ongoing atomic block1 transfer
// -> the message is handled by the BlockwiseTransfer FSM
if (v_blockwiseIdx >= 0)
{
f_EPTF_COAP_BlockwiseTransfer_in(v_blockwiseIdx, p_msg, v_block1OptionIdx);
// The stack indicates, that the request is automatically handled
v_COAP_Stack_autoHandled := true;
}
// If we don't have a BlockwiseTransfer FSM we dispatch an event to the entity to handle it
else
{
f_EPTF_COAP_dispatchEventForBlock1(p_msg.pdu.options[v_block1OptionIdx].block1, p_msg.eIdx, -1);
}
return true;
}
return false;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_cancel
//
// Purpose:
// This function handles the *cancel* event of a <COAP_Transaction> state machine instance
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will handle the event
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_cancel(in integer p_trIdx)
runs on EPTF_COAP_LGen_CT
{
if (p_trIdx < 0 or p_trIdx >= sizeof(v_COAP_trDB.data)) { return }
if (v_COAP_trDB.data[p_trIdx].state == RELIABLE_TX)
{
// cancel T retransmission
f_EPTF_COAP_tr_cancelT_retransmit(p_trIdx);
// next state: CLOSED
f_EPTF_COAP_tr_setState(p_trIdx, CLOSED);
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " cancel only handled in RELIABLE_ACK state"));
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_lifetime
//
// Purpose:
// This function handles the *T_lifetime* timer's timeout event of a <COAP_Transaction> state machine instance
//
// Parameters:
// pl_action - *in* <EPTF_ScheduledAction> - contains the index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will handle the event
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_lifetime(in EPTF_ScheduledAction pl_action, in integer pl_eventIndex)
runs on EPTF_COAP_LGen_CT
return boolean
{
var integer vl_trIdx := pl_action.actionId[0];
if (vl_trIdx < 0 or vl_trIdx >= sizeof(v_COAP_trDB.data)) { return false }
v_COAP_trDB.data[vl_trIdx].lifetimeTimer := -1;
if (v_COAP_trDB.data[vl_trIdx].state == RELIABLE_TX)
{
// cancel T retransmission
f_EPTF_COAP_tr_cancelT_retransmit(vl_trIdx);
// report trTimeout event
f_EPTF_COAP_rr_timeout(v_COAP_trDB.data[vl_trIdx].rrIdx);
// next state: CLOSED
f_EPTF_COAP_tr_setState(vl_trIdx, CLOSED);
}
f_EPTF_COAP_tr_remove(vl_trIdx);
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_retransmit
//
// Purpose:
// This function handles the *T_retransmit* timer's timeout event of a <COAP_Transaction> state machine instance
//
// Parameters:
// pl_action - *in* <EPTF_ScheduledAction> - contains the index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will handle the event
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_retransmit(in EPTF_ScheduledAction pl_action, in integer pl_eventIndex)
runs on EPTF_COAP_LGen_CT
return boolean
{
var integer vl_trIdx := pl_action.actionId[0];
if (vl_trIdx < 0 or vl_trIdx >= sizeof(v_COAP_trDB.data)) { return false }
v_COAP_trDB.data[vl_trIdx].retransmitTimer := -1;
if (ispresent(v_COAP_trDB.data[vl_trIdx].cache))
{
f_EPTF_COAP_tr_startT_retransmit(vl_trIdx);
f_EPTF_COAP_tr_send(v_COAP_trDB.data[vl_trIdx].cache, vl_trIdx);
v_COAP_stats.noRetransmissions := v_COAP_stats.noRetransmissions + 1;
}
else
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId, " cannot retransmit empty cache"));
}
return true;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_startT_retransmit
//
// Purpose:
// This function starts the *T_retransmit* timer of a particular <COAP_Transaction> instance
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will start the timer
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_startT_retransmit(in integer pl_trIdx)
runs on EPTF_COAP_LGen_CT
return boolean
{
var boolean retval;
var EPTF_ActionId vl_actionId;
var float vl_time := v_COAP_trDB.data[pl_trIdx].retransmitTimerValue;
vl_actionId[0] := pl_trIdx;
retval := f_EPTF_SchedulerComp_scheduleAction(
f_EPTF_SchedulerComp_snapshotTime() + vl_time,
refers(f_EPTF_COAP_tr_retransmit),
vl_actionId,
v_COAP_trDB.data[pl_trIdx].retransmitTimer
);
// start retransTimeout (TODO calculate next rentransmission)
v_COAP_trDB.data[pl_trIdx].retransmitTimerValue :=
v_COAP_trDB.data[pl_trIdx].retransmitTimerValue * tsp_EPTF_COAP_LGen_retransmitTimerFallbackMultiplier;
return retval;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_cancelT_retransmit
//
// Purpose:
// This function cancels the *T_retransmit* timer of a particular <COAP_Transaction> instance
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will cancel the timer
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_cancelT_retransmit(in integer pl_trIdx)
runs on EPTF_COAP_LGen_CT
{
if (v_COAP_trDB.data[pl_trIdx].retransmitTimer >= 0)
{
if(not f_EPTF_SchedulerComp_CancelEvent(v_COAP_trDB.data[pl_trIdx].retransmitTimer))
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId,": could not cancel timer"));
}
v_COAP_trDB.data[pl_trIdx].retransmitTimer := -1;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_startT_lifetime
//
// Purpose:
// This function starts the *T_lifetime* timer of a particular <COAP_Transaction> instance
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will start the timer
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_startT_lifetime(in integer pl_trIdx, in float pl_time)
runs on EPTF_COAP_LGen_CT
return boolean
{
var boolean retval;
var EPTF_ActionId vl_actionId;
vl_actionId[0] := pl_trIdx;
retval := f_EPTF_SchedulerComp_scheduleAction(
f_EPTF_SchedulerComp_snapshotTime() + pl_time,
refers(f_EPTF_COAP_tr_lifetime),
vl_actionId,
v_COAP_trDB.data[pl_trIdx].lifetimeTimer
);
return retval;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_cancelT_lifetime
//
// Purpose:
// This function cancels the *T_lifetime* timer of a particular <COAP_Transaction> instance
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will cancel the timer
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_cancelT_lifetime(in integer pl_trIdx)
runs on EPTF_COAP_LGen_CT
{
if (v_COAP_trDB.data[pl_trIdx].lifetimeTimer >= 0)
{
if(not f_EPTF_SchedulerComp_CancelEvent(v_COAP_trDB.data[pl_trIdx].lifetimeTimer))
{
f_EPTF_COAP_Logging_WARNING(log2str(%definitionId,": could not cancel timer"));
}
v_COAP_trDB.data[pl_trIdx].lifetimeTimer := -1;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_startT_rtt
//
// Purpose:
// This function starts the *T_rtt* timer to measure the round-trip time of the transaction
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will start the timer
//
// Related Types:
// <COAP_Transaction>
///////////////////////////////////////////////////////////
function f_EPTF_COAP_tr_startT_rtt(in integer pl_trIdx)
runs on EPTF_COAP_LGen_CT
{
v_COAP_trDB.data[pl_trIdx].rtt := T_EPTF_componentClock.read;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_COAP_tr_stopT_rtt
//
// Purpose:
// This function stops the *T_rtt* timer and reports the measure round-trip time
// via the <vf_COAP_rttIndication> <fcb_EPTF_COAP_rttIndication> call-back function
//
// Parameters:
// p_trIdx - *in* *integer* - index of the <COAP_Transaction> in the <COAP_Transaction_DB> that will measure RTT