/******************************************************************************/
// @copyright   Copyright Notification
//   No part may be reproduced except as authorized by written permission.
//   The copyright and the foregoing restriction extend to reproduction in all media.
//   (c) 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC).
//   All rights reserved.
// @version: IWD_23wk37
// $Date: 2023-07-19 14:52:19 +0200 (Wed, 19 Jul 2023) $
// $Rev: 36499 $
/******************************************************************************/

module CommonDefs {

  //----------------------------------------------------------------------------
  // type definitions:

  type bitstring                B1_Type        length(1) with { variant "FIELDLENGTH(1)" };
  type bitstring                B2_Type        length(2) with { variant "FIELDLENGTH(2)" };
  type bitstring                B3_Type        length(3) with { variant "FIELDLENGTH(3)" };
  type bitstring                B4_Type        length(4) with { variant "FIELDLENGTH(4)" };
  type bitstring                B5_Type        length(5) with { variant "FIELDLENGTH(5)" };
  type bitstring                B6_Type        length(6) with { variant "FIELDLENGTH(6)" };
  type bitstring                B7_Type        length(7) with { variant "FIELDLENGTH(7)" };
  type bitstring                B7_15_Type     length(7..15);    // NOTE: length restriction can only be a range but not two destinct lengths
  type bitstring                B8_Type        length(8) with { variant "FIELDLENGTH(8)" };
  type bitstring                B9_Type        length(9) with { variant "FIELDLENGTH(9)" };
  type bitstring                B10_Type       length(10) with { variant "FIELDLENGTH(10)" };
  type bitstring                B11_Type       length(11) with { variant "FIELDLENGTH(11)" };
  type bitstring                B12_Type       length(12) with { variant "FIELDLENGTH(12)" };
  type bitstring                B13_Type       length(13) with { variant "FIELDLENGTH(13)" };
  type bitstring                B14_Type       length(14) with { variant "FIELDLENGTH(14)" };
  type bitstring                B15_Type       length(15) with { variant "FIELDLENGTH(15)" };
  type bitstring                B16_Type       length(16) with { variant "FIELDLENGTH(16)" };
  type bitstring                B18_Type       length(18) with { variant "FIELDLENGTH(18)" };
  type bitstring                B20_Type       length(20) with { variant "FIELDLENGTH(20)" };
  type bitstring                B22_Type       length(22) with { variant "FIELDLENGTH(22)" };
  type bitstring                B24_Type       length(24) with { variant "FIELDLENGTH(24)" };
  type bitstring                B27_Type       length(27) with { variant "FIELDLENGTH(27)" };
  type bitstring                B28_Type       length(28) with { variant "FIELDLENGTH(28)" };
  type bitstring                B32_Type       length(32) with { variant "FIELDLENGTH(32)" };
  type bitstring                B36_Type       length(36) with { variant "FIELDLENGTH(36)" };
  type bitstring                B40_Type       length(40) with { variant "FIELDLENGTH(40)" };
  type bitstring                B41_Type       length(41) with { variant "FIELDLENGTH(41)" };
  type bitstring                B42_Type       length(42) with { variant "FIELDLENGTH(42)" };
  type bitstring                B43_Type       length(43) with { variant "FIELDLENGTH(43)" };
  type bitstring                B45_Type       length(45) with { variant "FIELDLENGTH(45)" };
  type bitstring                B47_Type       length(47) with { variant "FIELDLENGTH(47)" };
  type bitstring                B48_Type       length(48) with { variant "FIELDLENGTH(48)" };
  type bitstring                B56_Type       length(56) with { variant "FIELDLENGTH(56)" };
  type bitstring                B64_Type       length(64) with { variant "FIELDLENGTH(64)" };
  type bitstring                B80_Type       length(80) with { variant "FIELDLENGTH(80)" };
  type bitstring                B112_Type      length(112) with { variant "FIELDLENGTH(112)" };
  type bitstring                B128_Type      length(128) with { variant "FIELDLENGTH(128)" };
  type bitstring                B160_Type      length(160) with { variant "FIELDLENGTH(160)" };
  type bitstring                B184_Type      length(184) with { variant "FIELDLENGTH(184)" };
  type bitstring                B192_Type      length(192) with { variant "FIELDLENGTH(192)" };
  type bitstring                B256_Type      length(256) with { variant "FIELDLENGTH(256)" };
  type bitstring                B32_128_Type   length(32..128);

  type B128_Type                B128_Key_Type;      /* 128 bit security key */
  type B256_Type                B256_Key_Type;      /* 256 bit security key */

  type octetstring              O1_Type         length(1) with { variant "FIELDLENGTH(1)" };
  type octetstring              O2_Type         length(2) with { variant "FIELDLENGTH(2)" };
  type octetstring              O3_Type         length(3) with { variant "FIELDLENGTH(3)" };
  type octetstring              O4_Type         length(4) with { variant "FIELDLENGTH(4)" };
  type octetstring              O5_Type         length(5) with { variant "FIELDLENGTH(5)" };
  type octetstring              O6_Type         length(6) with { variant "FIELDLENGTH(6)" };
  type octetstring              O8_Type         length(8) with { variant "FIELDLENGTH(8)" };
  type octetstring              O9_Type         length(9) with { variant "FIELDLENGTH(9)" };
  type octetstring              O10_Type        length(10) with { variant "FIELDLENGTH(10)" };
  type octetstring              O13_Type        length(13) with { variant "FIELDLENGTH(13)" };
  type octetstring              O14_Type        length(14) with { variant "FIELDLENGTH(14)" };
  type octetstring              O15_Type        length(15) with { variant "FIELDLENGTH(15)" };
  type octetstring              O16_Type        length(16) with { variant "FIELDLENGTH(16)" };
  type octetstring              O28_Type        length(28) with { variant "FIELDLENGTH(28)" };
  type octetstring              O32_Type        length(32) with { variant "FIELDLENGTH(32)" };
  type octetstring              O43_Type        length(43) with { variant "FIELDLENGTH(43)" };

  type hexstring                H1_Type         length(1) with { variant "FIELDLENGTH(1)" };
  type hexstring                H2_Type         length(2) with { variant "FIELDLENGTH(2)" };
  type hexstring                H4_Type         length(4) with { variant "FIELDLENGTH(4)" };
  type hexstring                H12_Type        length(12) with { variant "FIELDLENGTH(12)" };
  type hexstring                H14_Type        length(14) with { variant "FIELDLENGTH(14)" };

  type O1_Type                  Octet_Type;
  type hexstring                HalfOctet_Type length(1) with { variant "FIELDLENGTH(1)" };

  type record of B8_Type B8_List_Type;

  type boolean Null_Type  (true);    // dummy type for 'typeless' fields in unions
  type boolean Dummy_Type (true);    // dummy type for temporary purposes only

  const integer tsc_UInt7Max  := 127;
  const integer tsc_UInt8Max  := 255;
  const integer tsc_UInt16Max := 65535;
  const integer tsc_UInt20Max := 1048575;
  const integer tsc_UInt24Max := 16777215;
  const integer tsc_UInt32Max := 4294967295;

  type integer  UInt_Type    (0 .. infinity);
  type integer  UInt8_Type   (0 .. tsc_UInt8Max);
  type integer  UInt16_Type  (0 .. tsc_UInt16Max);
  type integer  UInt20_Type  (0 .. tsc_UInt20Max);
  type integer  UInt24_Type  (0 .. tsc_UInt24Max);
  type integer  UInt32_Type  (0 .. tsc_UInt32Max);

  type Octet_Type       UE_TestLoopMode_Type;

  type charstring Char1_Type length (1);
  type charstring Char3_Type length (3);
  type record of Char1_Type Char1List_Type;
  type record of charstring CharStringList_Type;
  type set of charstring SetOfCharString_Type;

  type record of octetstring OctetStringList_Type;

  type record of bitstring BitStringList_Type;

  type record of integer IntegerList_Type;


  type record NameValue_Type {
    charstring Name,
    charstring Value
  };
  type set of NameValue_Type NameValueList_Type;

  const integer tsc_DirectionUL := 0;   /* acc. to 33.401 B.1.1 and B.2.1                @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, POS, UTRAN) */
  const integer tsc_DirectionDL := 1;   /* acc. to 33.401 B.1.1 and B.2.1                @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, POS, UTRAN) */
  const octetstring tsc_WLAN_SSID_AP1 := char2oct("3GPP WLAN InterWorking");                    /* @status    APPROVED (IMS) */

  type integer MAC_Direction_Type (tsc_DirectionDL, tsc_DirectionUL);   /* direction bit for calculation of MAC acc. to 24.301 cl. 9.5    @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, POS, UTRAN) */

  type enumerated IndicationAndControlMode_Type {enable, disable};

  type enumerated SinglePLMN_TestedType {SinglePLMN, MultiPLMN, MultiPLMNinPrimaryBand, MultiPLMNinSecondaryBand}; // @sic R5-123667 sic@
  type enumerated EUTRA_ATTACH_TESTED_Type { EPS_ATTACH_ONLY, COMBINED_ATTACH};
  type enumerated EUTRA_FDD_TDD_Mode_Type {FDD, TDD};
  type enumerated UTRAN_FDD_TDD_Type  {UTRAN_FDD, UTRAN_TDD};
  type enumerated RATComb_Tested_Type {EUTRA_UTRA, EUTRA_GERAN, EUTRA_Only};
  type enumerated RRCConnectionReleaseRequired_Type { rrcConnectionRelease, noRrcConnectionRelease };
  type enumerated NTN_Satellite_Type {ntn_None, ntn_GSO, ntn_NGSO}; //@sic R5s230512 sic@

  type enumerated NGC_CellId_Type {
    ngc_Cell_NonSpecific,
    ngc_CellA,
    ngc_CellB,
    ngc_CellC,
    ngc_CellD,
    ngc_CellE,
    ngc_CellF,
    ngc_CellG,
    ngc_CellH,
    ngc_CellI,
    ngc_CellJ
  };

  type enumerated NR_CellId_Type {
    nr_Cell_NonSpecific,
    nr_Cell1,
    nr_Cell2,
    nr_Cell3,
    nr_Cell4,
    nr_Cell6,
    nr_Cell10,
    nr_Cell11,
    nr_Cell12,
    nr_Cell13,
    nr_Cell14,
    nr_Cell23,
    nr_Cell28,
    nr_Cell29,
    nr_Cell30,
    nr_Cell31
  };

  type record of NR_CellId_Type NR_CellIdList_Type;    /* NOTE: there seems to be no need for any length restriction */

  type enumerated EUTRA_CellId_Type {
    eutra_Cell_NonSpecific,
    eutra_Cell1,
    eutra_Cell2,
    eutra_Cell3,
    eutra_Cell4,
    eutra_Cell6,
    eutra_Cell10,
    eutra_Cell11,
    eutra_Cell12,
    eutra_Cell13,
    eutra_Cell14,
    eutra_Cell23,
    eutra_Cell28,
    eutra_Cell29,
    eutra_Cell30,
    eutra_Cell31,
    eutra_CellA,
    eutra_CellB,
    eutra_CellC,
    eutra_CellD,
    eutra_CellE,
    eutra_CellG,
    eutra_CellH,
    eutra_CellI,
    eutra_CellJ,
    eutra_CellK,
    eutra_CellL,
    eutra_CellM
  };

  type record length (0..9) of EUTRA_CellId_Type  EUTRA_CellIdList_Type;

  type enumerated UTRAN_CellId_Type  {
    utran_CellDedicated (-1),
    utran_Cell5 (5),
    utran_Cell7 (7),
    utran_Cell8 (8),
    utran_Cell9 (9),
    utran34_Cell1 (1000),
    utran34_Cell2 (1001),
    utran34_Cell3 (1002),
    utran34_Cell4 (1003),
    utran34_Cell5 (1004),
    utran34_Cell6 (1005),
    utran34_Cell7 (1006),
    utran34_Cell8 (1007),
    utran34_CellA (2000),
    utran34_CellB (2001),
    utran34_CellC (2002),
    utran34_CellD (2003),
    utran34_CellE (2004),
    utran34_CellF (2005),
    utran34_CellG (2006),
    utran34_CellH (2007)
  };  // @sic R5-133563: added utran34_CellA/B/C... for 34.123-1 NAS tc sic@

  type record of UTRAN_CellId_Type  UTRAN_CellIdList_Type;

  type enumerated WLAN_CellId_Type {
    wlan_Cell_NonSpecific (-1),
    wlan_Cell27 (27),                  /* WLAN AP in EUTRA environment */
    wlan_Cell27b (272),                /* WLAN AP in EUTRA environment */
    wlan_Cell39 (39)                   /* WLAN AP in UTRA environment */
  };

  //Common delta types
  type record  UE_NR_DeltaValues_Type {
    DeltaValues_Type    DeltaPrimaryBand,
    DeltaValues_Type    DeltaSecondaryBand
  };

  type union AnyCellId_Type {
    EUTRA_CellId_Type           Eutra,
    NR_CellId_Type              Nr
    // to be extended when needed
  };

  type record DeltaValues_Type {
    /* Delta value for each frequency, by default for FR1 or when the frequency is not available the Delta value is set to 0. */
    integer DeltaNRf1,
    integer DeltaNRf2,
    integer DeltaNRf3,
    integer DeltaNRf4
  };

  //----------------------------------------------------------------------------

  type integer IP_DrbId_Type;           /* DRB identity type common for all RATs:
                                         * - for EUTRA it corresponds to the ASN.1 type DRB-Identity
                                         * - for UTRAN it corresponds to the ASN.1 type RB-Identity and values are as defined in TS 34.123-3 Table 8.2.4.1
                                         * - for GERAN the NSAPI value (type record NSAPI) may be used
                                         * NOTE: this is introduced to simplify the dependencies (i.e. to keep IP_ASP_TypeDefs independent from any RAT specific type definitions) */

  type record IP_EUTRA_DrbInfo_Type {
    EUTRA_CellId_Type   CellId,         /* data is routed to a specific cell regardless of whether the same DRB is configured in any other cell */
    IP_DrbId_Type       DrbId  optional /* mandatory at the system interface */
  };

  type record IP_UTRAN_GERAN_DrbInfo_Type {
    integer             CellId,
    IP_DrbId_Type       DrbId  optional /* mandatory at the system interface */
  };

  type record IP_WLAN_DrbInfo_Type {
    integer             CellId
  };

  type record IP_ePDG_IPsecTunnelInfo_Type {
    PDN_Index_Type      PdnId           /* 'index name' of PDN associated to the IPsec tunnel, e.g. for SS to distinguish routing of IP packets in case of more than one IPsec tunnel
                                         * NOTE: In general only 'ePDG_XXX' values shall be used */

  };

  type record QosFlow_Identification_Type {
    integer PDU_SessionId,     /* TS 24.007 clause 11.2.3.1b */
    integer QFI                /* TS 24.501 Table 11.2.3.1c.1 */
  };

  type record IP_NR_QosFlowInfo_Type {
    NR_CellId_Type              CellId,                 /* data is routed to a specific cell regardless of whether the same DRB is configured in any other cell */
    QosFlow_Identification_Type QosFlow optional        /* mandatory at the system interface */
  };

  type record IP_EUTRA_QosFlowInfo_Type {
    EUTRA_CellId_Type           CellId,                 /* data is routed to a specific cell regardless of whether the same DRB is configured in any other cell */
    QosFlow_Identification_Type QosFlow optional        /* mandatory at the system interface */
  };

  type record IP_NR_DrbInfo_Type {
    NR_CellId_Type      CellId,
    IP_DrbId_Type       DrbId  optional /* mandatory at the system interface */
  };

  type union IP_DrbInfo_Type {
    IP_EUTRA_DrbInfo_Type           Eutra,
    IP_EUTRA_QosFlowInfo_Type       Eutra5GC,       /* used when SDAP is configured in non-transparent mode at the SS */
    IP_UTRAN_GERAN_DrbInfo_Type     Utran,
    IP_UTRAN_GERAN_DrbInfo_Type     Geran,
    IP_NR_QosFlowInfo_Type          Nr5GC,          /* used when SDAP is configured in non-transparent mode at the SS @sic R5-188107, R5w190005r1 sic@ */
    IP_NR_DrbInfo_Type              NrEPC,          /* used when NR is connected to EPC (S1-U interface) or when SDAP is configured in transparent mode at the SS @sic R5w190118 sic@ */
    IP_WLAN_DrbInfo_Type            Wlan,           /* @sic R5w160107 slide 7 sic@ */
    IP_ePDG_IPsecTunnelInfo_Type    IPsecTunnel     /* @sic R5w160107 slide 7 sic@ */
  };

  //----------------------------------------------------------------------------

  type enumerated GPRS_CipheringAlgorithm_Type {
    gea0(0),
    gea2(2),
    gea3(3),
    gea4(4)
  };

  type O4_Type  MessageAuthenticationCode;                /* 24.301 cl. 9.5 */
  type O4_Type  NasCount_Type;

  type B32_Type PdcpCountValue_Type;

  type enumerated IPCAN_RAN_Type {              /* radio access network technology used by the IPCAN PTC */
    GERAN,
    UTRAN_FDD,
    UTRAN_TDD,
    EUTRA_FDD,
    EUTRA_TDD,
    WLAN,                                       /* @sic R5-163201 sic@ */
    NR                                          /* @sic R5-188107 sic@ */
  };

  // To indicate which PTCs are configured (EUTRA alone is included for completeness)
  type enumerated IRAT_ConfiguredPTCs_Type { EUTRA_Only, EUTRA_UTRAN, EUTRA_GERAN, EUTRA_UTRAN_GERAN, EUTRA_CDMA2000, UTRAN_Only, UTRAN_GERAN, EUTRA_WLAN, UTRAN_WLAN, WLAN_Only, NR5GC_WLAN }

  const float tsc_GuardTimePreamble := 180.0;
  const float tsc_GuardTimePreamble_12min := tsc_GuardTimePreamble * int2float(4); // @sic R5s200494 sic@

  // definitions needed for IP and IMS handling
  const integer tsc_NoOfPDNs := 3;    /* @sic R5s191074 sic@ */
  const integer tsc_NoOfIMSPDNs := 2; /* @sic R5s201177 sic@ */

  const integer tsc_Index_IMS1 := 0;
  const integer tsc_Index_IMS2 := 1;

  type enumerated PDN_Index_Type {   /* 'index name' associated to a PDN:
                                        The major purpose is to associate a PDN specific set of IP addresses to the given PDN (e.g. UE addresses, P-CSCF address etc.);
                                        in general there are one or two PDNs configured at the same time and - from TTCN point of view - the IMS PDN is considered to be the first one;
                                        a second PDN may be configured in case of emergency call or e.g. for XCAP signalling;
                                        the 'internet PDN' (according to TS 36.508 clause 4.5.2) is considered as (optional) second PDN during initial registration and gets released after initial registration;
                                        in case of WLAN a separate group of index names is used to distinguish the different configuration of the emulated IP network */
    PDN_1 (0),       /* "default" PDN being kept connected to during a test case (in case of LTE in general the IMS PDN) */
    PDN_2 (1),       /* second PDN: during initial registration (TS 36.508 clause 4.5.2) for LTE and "multiple PDN' this is the internet PDN;
                        after initial registration it is used if needed according to the test purpose (e.g. emergency call) */
    PDN_2a,          /* used for the special case when the UE IP address of the second PDN changes in a test case */
    PDN_Internet,    /* mainly used as alias for PDN2 during initial registration */
    ePDG_IMS1,       /* WLAN: PDN for 'normal' IMS */
    ePDG_IMS2,       /* WLAN: PDN for emergency IMS (in general) */
    ePDG_XCAP,       /* WLAN: PDN for XCAP in case of XCAP server being part of 3GPP-network
                        NOTE: In contrast to LTE for WLAN there is a different IP architecture to be consider by TTCN for XCAP and IMS emergency */
    ePDG_Internet,   /* place-holder for WLAN-offload scenarios */
    nrPDN_Internet,  /* mainly used as alias during initial registration in ENDC  @sic R5s191074 sic@ */
    PDN_3 (2),       /* used in ENDC and 5GC for the third PDN  @sic R5s191074 sic@ */
    PDN_4 (3),       /* used in 5GC for the URLLC PDN  @sic R5-221467 sic@ */
    PDN_5 (4),       /* used in 5GC for the MIoT PDN  @sic R5-221467 sic@ */
    PDN_6 (5)        /* used in 5GC for the V2X PDN  @sic R5-221467 sic@ */
  };

  const integer tsc_EUTRA_MaxEARFCN := 65535; // @sic R5-173669 moved from UTRANCommonDefs sic@

  /* @sic R5s220330 sic@ */
  const integer tsc_Max_NR_PDCP_SDU_size  := 9000;  // TS38.323 cl. 4.3.1
  const integer tsc_Max_LTE_PDCP_SDU_size  := 8188; // TS36.323 cl. 4.3.1

  //----------------------------------------------------------------------------

  // **** C-RNTI: 16 bit for all EUTRA/NBIOT/NR; same constants to be used for NR unless there is a need for NR-specifc values in which case the constants shall have an NR prefix ****
  type UInt16_Type RNTI_Value_Type;                   /* corresponds to NR ASN.1:  RNTI-Value ::= INTEGER (0..65535) */
  type B16_Type RNTI_B16_Type;

  const RNTI_Value_Type tsc_C_RNTI_Value1  := hex2int('1001'H);   /* '1001'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value2  := hex2int('1034'H);   /* '1034'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value3  := hex2int('1111'H);   /* '1111'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value4  := hex2int('1FF1'H);   /* '1FF1'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value5  := hex2int('04D2'H);   /* '04D2'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value6  := hex2int('0929'H);   /* '0929'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value7  := hex2int('0D80'H);   /* '0D80'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value8  := hex2int('11D7'H);   /* '11D7'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value9  := hex2int('162E'H);   /* '162E'H acc. to TS 36.523-3 table 7.1.1-1 */
  const RNTI_Value_Type tsc_C_RNTI_Value10 := hex2int('1A85'H);   /* '1A85'H acc. to TS 36.523-3 table 7.1.1-1 */


  const RNTI_B16_Type tsc_C_RNTI_Def   := int2bit(tsc_C_RNTI_Value1, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def2  := int2bit(tsc_C_RNTI_Value2, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def3  := int2bit(tsc_C_RNTI_Value3, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def4  := int2bit(tsc_C_RNTI_Value4, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def5  := int2bit(tsc_C_RNTI_Value5, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def6  := int2bit(tsc_C_RNTI_Value6, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def7  := int2bit(tsc_C_RNTI_Value7, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def8  := int2bit(tsc_C_RNTI_Value8, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def9  := int2bit(tsc_C_RNTI_Value9, 16);
  const RNTI_B16_Type tsc_C_RNTI_Def10 := int2bit(tsc_C_RNTI_Value10, 16);

  template (present) octetstring cr_Octet10_Any  := ? length(10);   /* @status    APPROVED (LTE) */

  //----------------------------------------------------------------------------
  // constant to generate PRBS sequence
  const octetstring tsc_RandomPRBS :=
      'FFE665A5C5CA3452085408ABEECE4B0B813FD337873F2CD1E29AE91BD6C8E14F'O
    & 'DE630F8195688EBE465F09816A8EEB1B83953DD362DAE3B06D5B76D8E3E53087'O
    & 'EA645A09017FD99C3CACBB46DF1CD61DA9C435F89943DF9CC34ADEE31AD6E24F'O
    & 'A1903D53778D949742750DD49DE9CE9E430AD448A14575D89C16025508814020'O //octets 0 .. 127
    & '0555DDC9CBCB9EC31F833F866A5BA390680EAB11282EAE44F5E7658F6B247A0C'O
    & '54A21057F73278595C235077F267A59097E8CEB4EDE49A16FDB36D2485EA3107'O
    & 'D59DC360700D5488BEB9B96C24AF44DF498BC135788C14A8BBEC64A5EF64DA1C'O
    & '5608FEB312D7B738D3E2CFB4C74A7458A3EF9B3C79F3CD348740DFE330780C01'O //octets 128 .. 255
    & 'FFCCCB4B8B9468A410A81157DD9C9617027FA66F0E7E59A3C535D237AD91C29F'O
    & 'BCC61F032AD11D7C8CBE1302D51DD637072A7BA6C5B5C760DAB6EDB1C7CA610F'O
    & 'D4C8B41202FFB3387959768DBE39AC3B53886BF13287BF398695BDC635ADC49F'O
    & '43207AA6EF1B292E84EA1BA93BD39D3C8615A891428AEBB1382C04AA11028040'O //octets 256 .. 383
    & '0AABBB9397973D863F067F0CD4B74720D01D5622505D5C89EBCECB1ED648F418'O
    & 'A94420AFEE64F0B2B846A0EFE4CF4B212FD19D69DBC9342DFB66DA490BD4620F'O
    & 'AB3B86C0E01AA9117D7372D8495E89BE9317826AF118295177D8C94BDEC9B438'O
    & 'AC11FD6625AF6E71A7C59F698E94E8B147DF3678F3E79A690E81BFC660F01803'O //octets 384 .. 511
    & 'FF9996971728D148215022AFBB392C2E04FF4CDE1CFCB3478A6BA46F5B23853F'O
    & '798C3E0655A23AF9197C2605AA3BAC6E0E54F74D8B6B8EC1B56DDB638F94C21F'O
    & 'A991682405FF6670F2B2ED1B7C735876A710D7E2650F7E730D2B7B8C6B5B893E'O
    & '8640F54DDE36525D09D4375277A73A790C2B51228515D7627058095422050080'O //octets 512 .. 639
    & '155777272F2E7B0C7E0CFE19A96E8E41A03AAC44A0BAB913D79D963DAC91E831'O
    & '5288415FDCC9E165708D41DFC99E96425FA33AD3B792685BF6CDB49217A8C41F'O
    & '56770D81C0355222FAE6E5B092BD137D262F04D5E23052A2EFB19297BD936871'O
    & '5823FACC4B5EDCE34F8B3ED31D29D1628FBE6CF1E7CF34D21D037F8CC1E03007'O //octets 640 .. 767
    & 'FF332D2E2E51A29042A0455F7672585C09FE99BC39F9668F14D748DEB6470A7E'O
    & 'F3187C0CAB4475F232F84C0B547758DC1CA9EE9B16D71D836ADBB6C71F29843F'O
    & '5322D0480BFECCE1E565DA36F8E6B0ED4E21AFC4CA1EFCE61A56F718D6B7127D'O
    & '0C81EA9BBC6CA4BA13A86EA4EF4E74F21856A2450A2BAEC4E0B012A8440A0100'O //octets 768 .. 895
    & '2AAEEE4E5E5CF618FC19FC3352DD1C834075588941757227AF3B2C7B5923D062'O
    & 'A51082BFB993C2CAE11A83BF933D2C84BF4675A76F24D0B7ED9B69242F51883E'O
    & 'ACEE1B03806AA445F5CDCB61257A26FA4C5E09ABC460A545DF63252F7B26D0E2'O
    & 'B047F59896BDB9C69F167DA63A53A2C51F7CD9E3CF9E69A43A06FF1983C0600F'O //octets 896 .. 1023
    & 'FE665A5C5CA3452085408ABEECE4B0B813FD337873F2CD1E29AE91BD6C8E14FD'O
    & 'E630F8195688EBE465F09816A8EEB1B83953DD362DAE3B06D5B76D8E3E53087E'O
    & 'A645A09017FD99C3CACBB46DF1CD61DA9C435F89943DF9CC34ADEE31AD6E24FA'O
    & '1903D53778D949742750DD49DE9CE9E430AD448A14575D89C160255088140200'O //octets 1024 .. 1151
    & '555DDC9CBCB9EC31F833F866A5BA390680EAB11282EAE44F5E7658F6B247A0C5'O
    & '4A21057F73278595C235077F267A59097E8CEB4EDE49A16FDB36D2485EA3107D'O
    & '59DC360700D5488BEB9B96C24AF44DF498BC135788C14A8BBEC64A5EF64DA1C5'O
    & '608FEB312D7B738D3E2CFB4C74A7458A3EF9B3C79F3CD348740DFE330780C01F'O //octets 1152 .. 1279
    & 'FCCCB4B8B9468A410A81157DD9C9617027FA66F0E7E59A3C535D237AD91C29FB'O
    & 'CC61F032AD11D7C8CBE1302D51DD637072A7BA6C5B5C760DAB6EDB1C7CA610FD'O
    & '4C8B41202FFB3387959768DBE39AC3B53886BF13287BF398695BDC635ADC49F4'O
    & '3207AA6EF1B292E84EA1BA93BD39D3C8615A891428AEBB1382C04AA110280400'O //octets 1280 .. 1407
    & 'AABBB9397973D863F067F0CD4B74720D01D5622505D5C89EBCECB1ED648F418A'O
    & '94420AFEE64F0B2B846A0EFE4CF4B212FD19D69DBC9342DFB66DA490BD4620FA'O
    & 'B3B86C0E01AA9117D7372D8495E89BE9317826AF118295177D8C94BDEC9B438A'O
    & 'C11FD6625AF6E71A7C59F698E94E8B147DF3678F3E79A690E81BFC660F01803F'O //octets 1408 .. 1535
    & 'F9996971728D148215022AFBB392C2E04FF4CDE1CFCB3478A6BA46F5B23853F7'O
    & '98C3E0655A23AF9197C2605AA3BAC6E0E54F74D8B6B8EC1B56DDB638F94C21FA'O
    & '991682405FF6670F2B2ED1B7C735876A710D7E2650F7E730D2B7B8C6B5B893E8'O
    & '640F54DDE36525D09D4375277A73A790C2B51228515D76270580954220500801'O //octets 1536 .. 1663
    & '55777272F2E7B0C7E0CFE19A96E8E41A03AAC44A0BAB913D79D963DAC91E8315'O
    & '288415FDCC9E165708D41DFC99E96425FA33AD3B792685BF6CDB49217A8C41F5'O
    & '6770D81C0355222FAE6E5B092BD137D262F04D5E23052A2EFB19297BD9368715'O
    & '823FACC4B5EDCE34F8B3ED31D29D1628FBE6CF1E7CF34D21D037F8CC1E03007F'O //octets 1664 .. 1791
    & 'F332D2E2E51A29042A0455F7672585C09FE99BC39F9668F14D748DEB6470A7EF'O
    & '3187C0CAB4475F232F84C0B547758DC1CA9EE9B16D71D836ADBB6C71F29843F5'O
    & '322D0480BFECCE1E565DA36F8E6B0ED4E21AFC4CA1EFCE61A56F718D6B7127D0'O
    & 'C81EA9BBC6CA4BA13A86EA4EF4E74F21856A2450A2BAEC4E0B012A8440A01002'O //octets 1792 .. 1919
    & 'AAEEE4E5E5CF618FC19FC3352DD1C834075588941757227AF3B2C7B5923D062A'O
    & '51082BFB993C2CAE11A83BF933D2C84BF4675A76F24D0B7ED9B69242F51883EA'O
    & 'CEE1B03806AA445F5CDCB61257A26FA4C5E09ABC460A545DF63252F7B26D0E2B'O
    & '047F59896BDB9C69F167DA63A53A2C51F7CD9E3CF9E69A43A06FF1983C0600'O;  //octets 1920 .. 2046

  const charstring tsc_AT_ResultOK := "<CR><LF>OK<CR><LF>";
  const charstring tsc_Fox := "The quick brown fox jumps over the lazy dog's back. Kaufen Sie Ihrer Frau vier bequeme Pelze. - 0123456789 - THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG'S BACK.";
  const charstring tsc_Fox_PDU := "06812222222222"
                                & "11000A9174097538740000A7a054741914afa7c76b9058febebb41e6371ea4aeb7e173d0db5e9683"
                                & "e8e832881dd6e741e4f7f9340789c3e3b50bb40cd7cd6537689a2e83926879590e32cac375903d5d"
                                & "9683c4e578bddc2e83a065b6beec02b540b0986c46abd96eb81ca805a2228ba06835395c8284d2e7"
                                & "d509323eb12065b5099d829ed6a21444451641cca0360b223e8fa72948181c2e5d";
  const charstring tsc_FoxShort := "The quick brown fox jumps over the lazy dog's back. Kaufen Sie Ihrer Frau vier bequeme Pelze. 0123456789 - 153 chars - 134 octets for  SMS concatenation.";

  const charstring tsc_CarriageReturnLineFeed := char(0,0,0,13) & char(0,0,0,10);

  const octetstring tsc_Oct1000_0 := int2oct(0, 1000); /* @sic R5s230084 sic@
                                                          @status    APPROVED (NR5GC) */

  //----------------------------------------------------------------------------


  /* Verdict control */
  type enumerated VerdictCtrl_Type {
    normal,                                     /* verdict assignments as for normal L3 signalling test */
    layer2                                      /* verdict assignments for layer2 test: FAIL for unexpected events on DRB ports  */
  };

  type enumerated HarqErrorHandling_Type {
    ignore,                                     /* ignore HARQ error indications */
    raiseInconc,                                /* assign INCONC when there is a HARQ error indication */
    allowOneRetransmission                      /* allow up-to one harq retransmission
                                                   @sic R5s110176 BASELINE MOVING 2011 sic@ */
  };

  //----------------------------------------------------------------------------

  type integer LineNo_Type;

  /*
   * @desc      local function
   * @param     p_FileName
   * @param     p_LineNo
   * @param     p_Msg
   * @return    charstring
   */
  function fl_FormatLog(charstring p_FileName,
                        LineNo_Type p_LineNo,
                        charstring p_Msg) return charstring
  {
    var charstring v_LineNoStr := int2str(p_LineNo);

    return p_FileName & ":" & v_LineNoStr & ": " & p_Msg;   /* common "UNIX style" format as e.g. used by grep */

  }

  //----------------------------------------------------------------------------
  /*
   * @desc      function for common error logging
   * @param     p_FileName
   * @param     p_LineNo
   * @param     p_Msg
   */
  function f_ErrorLog(charstring p_FileName,
                      LineNo_Type p_LineNo,
                      charstring p_Msg)
  {
    log(fl_FormatLog(p_FileName, p_LineNo, p_Msg));
  };

  //----------------------------------------------------------------------------
  /*
   * @desc      common function for verdict assignment
   * @param     p_Verdict
   * @param     p_FileName
   * @param     p_LineNo
   * @param     p_Msg
   */
  function f_SetVerdict(verdicttype p_Verdict,
                        charstring p_FileName,
                        LineNo_Type p_LineNo,
                        charstring p_Msg)
  {
    var charstring v_OutputLine := fl_FormatLog(p_FileName, p_LineNo, p_Msg);
    setverdict(p_Verdict, v_OutputLine);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      Common functions to be called in case unrecoverable errors
   *            (i.e. runtimer errors generated by TTCN)
   * @param     p_FileName
   * @param     p_LineNo
   * @param     p_Msg
   */
  function FatalError(charstring p_FileName,
                      LineNo_Type p_LineNo,
                      charstring p_Msg)
  {
    // setverdict(inconc);  // setverdict causes problems when FatalError is used in a function called from within a template
    f_ErrorLog(p_FileName, p_LineNo, p_Msg);
    testcase.stop (p_Msg); // This operation now defined in TTCN3 v4.2.1
  };

  /*
   * @desc      set verdict inconc in cases when no pass/fail is possible e.g. due to wrong PICS/PIXIT
   *            NOTE: as there is no need to evaluate any component specific information ans as "self.kill" can be used to terminate the test case
   *                  (resulting in the final verdict 'inconc') this function is independent from any component and can be call from everywhere where 'setverdict' or 'self.kill' are allowed
   * @param     p_FileName
   * @param     p_LineNo
   * @param     p_Msg
   */
  function f_SetVerdictInconc(charstring p_FileName,
                              LineNo_Type p_LineNo,
                              charstring p_Msg)
  {
    f_SetVerdict(inconc, p_FileName, p_LineNo, p_Msg);
    self.kill;    // => test case will be terminated immediately
  }



  //----------------------------------------------------------------------------
  /*
   * @desc      Common function to delay the test case for the given time
   * @param     p_DelayTime
   */
  function f_Delay ( float p_DelayTime )
  {
    timer t_Delay;

    t_Delay.start ( p_DelayTime );
    t_Delay.timeout;
  };

  //----------------------------------------------------------------------------
  /*
   * @desc      return index of the first occurance of the given value in the list or -1 if not found
   * @param     p_IntegerList
   * @param     p_Val
   * @return    integer
   */
  function f_IntegerList_Search(IntegerList_Type p_IntegerList,
                                integer p_Val) return integer
  {
    var integer i;

    for (i:=0; i < lengthof(p_IntegerList); i:= i+1) {
      if (p_IntegerList[i] == p_Val) {
        return i;
      }
    }
    return -1;   /* @sic R5s190465 sic@ */
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      return log2 rounded up to the next integer
   * @param     p_Val
   * @return    upperbound(log2(p_Val))
   */
  function f_CeilLog2(integer p_Val) return integer
  {
    var integer N := 1;
    var integer i := 0;

    if (p_Val > 0) {
      while (N < p_Val) {
        N := N * 2;
        i := i + 1;
      }
    }
    return i;
  }

  /*
   * @desc      return log2 rounded down to the next integer
   * @param     p_Val
   * @return    lowerbound(log2(p_Val))
   */
  function f_FloorLog2(integer p_Val) return integer
  {
    return f_CeilLog2(p_Val + 1) - 1;   // see e.g. wikipedia
  }

  /*
   * @desc      return Base ^ Exponent
   *            NOTE: current implementation serves positive integer values only
   * @param     p_Base
   * @param     p_Exponent
   * @return    integer
   */
  function f_Power(UInt_Type p_Base,
                   UInt_Type p_Exponent) return UInt_Type
  {
    var integer i;
    var UInt_Type v_Result := 1;
    for (i := 0; i < p_Exponent; i := i + 1) {
      v_Result := v_Result * p_Base;
    }
    return v_Result;
  }

  /*
   * @desc      return float value rounded with tie-breaking away from zero (i.e. x.5 is rounded up for positive values but rounded down for negative values)
   * @param     p_Float
   * @return    integer
   * @status    APPROVED (ENDC, NR5GC, NR5GC_IRAT)
   */
  function f_Round(float p_Float) return integer
  {
    var integer v_Result;

    if (p_Float >= 0.0) {
      v_Result := float2int(p_Float + 0.5);
    } else {                    // @sic R5s200469: negative values sic@
      v_Result := float2int(p_Float - 0.5);
    }
    return v_Result;
  }

  //----------------------------------------------------------------------------

  function f_TemplateInt2Bit(template (present) integer p_Val,
                             integer p_Length) return template (present) bitstring
  { /* Auxiliary function
     * note: there is no possibility in TTCN-3 to check whether a template parameter
     *       which is not a value is "*", "?" or omit
     *       => we restrict p_Val to "template (present)", i.e it shall be a value or "?" */
    if (isvalue(p_Val)) {
      return int2bit(valueof(p_Val), p_Length);
    } else {
      return ?;
    }
  }

  function f_TemplateInt2Str(template (present) integer p_Val) return template (present) charstring
  {
    if (isvalue(p_Val)) {
      return int2str(valueof(p_Val));
    } else {
      return ?;
    }
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      returns index of first occurency of any char of p_CharList in p_String starting from p_StartIndex;
   *            returns -1 if there is no occurency
   * @param     p_String
   * @param     p_CharList
   * @param     p_StartIndex
   * @return    integer
   */
  function f_StringFindChar(charstring p_String,
                            Char1List_Type p_CharList,
                            UInt_Type p_StartIndex := 0) return integer
  {
    var integer v_NoOfChars := lengthof(p_CharList);
    var integer v_Index;
    var integer i;
    var Char1_Type v_Char;

    if (v_NoOfChars == 0) {
      return -1;
    }

    for (v_Index:=p_StartIndex; v_Index<lengthof(p_String); v_Index:=v_Index+1) {
      v_Char := p_String[v_Index];
      for (i:=0; i<v_NoOfChars; i:=i+1) {
        if (v_Char == p_CharList[i]) {
          return v_Index;
        }
      }
    }
    return -1;
  }

  function fl_StringToUpperOrLower(boolean p_ToLower,
                                   charstring p_String) return charstring
  {
    var integer i;
    var integer v_StrLen := lengthof(p_String);
    var integer v_Value;
    var charstring v_String := "";

    for (i := 0; i < v_StrLen; i := i+1) {
      v_Value := char2int(p_String[i]);
      if (p_ToLower) {
        if ((64 < v_Value) and (v_Value < 91)) {
          v_Value := v_Value + 32;
        }
      } else {
        if ((96 < v_Value) and (v_Value < 123)) {
          v_Value := v_Value - 32;
        }
      }
      v_String[i] := int2char(v_Value);
    }
    return v_String;
  }

  function f_StringToLower(charstring p_String) return charstring
  {
    return fl_StringToUpperOrLower(true, p_String);
  }

  function f_StringToUpper(charstring p_String) return charstring
  {
    return fl_StringToUpperOrLower(false, p_String);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      returns list of strings after split
   * @param     p_String
   * @param     p_SplitCharList
   * @return    CharStringList_Type
   */
  function f_StringSplit(charstring p_String,
                         Char1List_Type p_SplitCharList) return CharStringList_Type
  {
    var CharStringList_Type v_StringList := {};
    var integer v_Index;
    var integer v_SubStrLen;
    var integer v_StartIndex := 0;
    var integer v_StrLen := lengthof(p_String);
    var integer v_StrCnt := 0;
    var boolean v_Break := false;

    if (p_String != "") {   // @sic R5s170544 sic@
      while (not v_Break) {
        v_Index := f_StringFindChar(p_String, p_SplitCharList, v_StartIndex);
        if (v_Index<0) {
          v_SubStrLen := v_StrLen - v_StartIndex;
          v_Break := true;
        } else {
          v_SubStrLen := v_Index - v_StartIndex;
        }
        v_StringList[v_StrCnt] := substr(p_String, v_StartIndex, v_SubStrLen);
        v_StrCnt := v_StrCnt + 1;
        v_StartIndex := v_Index + 1;  // skip the split char
      }
    }
    return v_StringList;
  }

  /*
   * @desc      similar as f_StringSplit but the delimiter is a string of potentially more than one character
   * @param     p_Text
   * @param     p_Delimitor         (default value: "\r\n")
   * @return    CharStringList_Type
   */
  function f_StringSplitLines(charstring p_Text,
                              charstring p_Delimitor := "\r\n") return CharStringList_Type
  {
    var charstring v_Text := p_Text;
    var CharStringList_Type v_CharStringList1;
    var CharStringList_Type v_CharStringList2 := {};
    var charstring v_Expression := "(*)(" & p_Delimitor & ")(*)";
    var integer i := 0;
    var integer N;

    while (regexp(v_Text, v_Expression, 1) != "") {
      v_CharStringList1[i] := regexp(v_Text, v_Expression, 2);
      v_Text := regexp(v_Text, v_Expression, 0);
      i := i + 1;
    }
    v_CharStringList1[i] := v_Text;
    N := i + 1;
    for (i := 0; i < N; i := i + 1) {   // TITAN ISSUE: Titan does not allow "{ v_String } & v_CharStringList1", therefore we need to change the order of the array
      v_CharStringList2[i] := v_CharStringList1[N-i-1];
    }
    return v_CharStringList2;
  }

  function f_StringJoin(CharStringList_Type p_StringList,
                        charstring p_JoinString := " ") return charstring
  { /* similar to TCL's join function,  but skips empty strings */
    var CharStringList_Type v_StringList;
    var charstring v_String := "";
    var integer i;
    var integer k := 0;

    for (i:=0; i < lengthof(p_StringList); i := i+1) {
      if (p_StringList[i] != "") {
        v_StringList[k] := p_StringList[i];
        k := k+1;
      }
    }
    if (k > 0) {
      for (i:=0; i < k - 1; i := i+1) {
        v_String := v_String & v_StringList[i] & p_JoinString;
      }
      v_String := v_String & v_StringList[i];
    }
    return v_String;
  }

  function f_CharStringList_Add(CharStringList_Type p_StringList,
                                charstring p_NewString) return CharStringList_Type
  {
    var integer v_Length := lengthof(p_StringList);
    var CharStringList_Type v_StringList := p_StringList;

    v_StringList[v_Length] := p_NewString;
    return v_StringList;
  }

  function f_CharStringList_Remove(CharStringList_Type p_StringList,
                                   template (present) charstring p_Pattern) return CharStringList_Type
  {
    var CharStringList_Type v_NewList := {};
    var integer k := 0;
    var integer i;

    for (i:=0; i < lengthof(p_StringList); i := i+1) {
      if (not match(p_StringList[i], p_Pattern)) {
        v_NewList[k] := p_StringList[i];
        k := k + 1;
      }
    }
    return v_NewList;
  }

  //----------------------------------------------------------------------------

  function f_ConvertBoolToBit(boolean p_Bool) return B1_Type
  {
    var B1_Type v_Bit := '0'B;
    if (p_Bool) {
      v_Bit := '1'B;
    }
    return v_Bit;
  }

  //----------------------------------------------------------------------------

  function f_ConvertStrToBit(charstring p_Charstring) return bitstring
  {
    var integer i;
    var bitstring v_ReturnBitString := ''B;

    for (i := 0; i<lengthof(p_Charstring); i := i+1) {
      v_ReturnBitString := v_ReturnBitString & int2bit(str2int(p_Charstring[i]), 1);
    }
    return v_ReturnBitString;
  }

  //----------------------------------------------------------------------------

  function f_Char2Bit(charstring p_Char) return bitstring
  {
    return oct2bit(char2oct(p_Char));
  }

  function f_Unichar2Bit(universal charstring p_Unichar) return bitstring
  {
   return oct2bit(unichar2oct(p_Unichar));
  }

  function f_XsdString2Bit(universal charstring p_XsdString) return bitstring
  { /* Alias function assuming XSD.String to be universal charstring;
       XSD.String is not used as type for p_XsdString to avoid import of XSD.ttcn */
    return f_Unichar2Bit(p_XsdString);
  }

  function f_Bit2Char(bitstring p_BitString) return charstring
  {
    return oct2char(bit2oct(p_BitString));
  }

  function f_Bit2Unichar(bitstring p_BitString) return universal charstring
  {
    return oct2unichar(bit2oct(p_BitString));
  }

  function f_Bit2XsdString(bitstring p_BitString) return universal charstring
  { /* Alias function assuming XSD.String to be universal charstring;
       XSD.String is not used as return type to avoid import of XSD.ttcn */
    return f_Bit2Unichar(p_BitString);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      return octet-aligned bitstring
   * @param     p_Bitstring
   * @return    bitstring
   */
  function f_OctetAlignedBitString(bitstring p_Bitstring) return bitstring
  { // @sic R5s100324 change 3 sic@
    var bitstring v_Bitstring := p_Bitstring;
    var integer v_BitLength := lengthof(p_Bitstring);
    var integer v_PaddingLength;
    var integer i;

    if ((v_BitLength mod 8) > 0) {        // if not already byte aligned
      v_PaddingLength := 8 - (v_BitLength mod 8);
      for (i:=0; i < v_PaddingLength; i := i+1) {
        v_Bitstring := v_Bitstring & '0'B;
      }
    }

    return v_Bitstring;
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      function to extract output string  from random test pattern of a certain length and at a starting point
   * @param     p_Start
   * @param     p_N
   * @return    octetstring
   */
  function f_GetN_OctetsFromPRBS(UInt_Type p_Start,
                                 UInt_Type p_N)
    return octetstring
  { /* @sic R5s180289: code optimisation sic@ */
    var integer v_LengthOfPRBS := lengthof(tsc_RandomPRBS);
    var integer v_Start := p_Start mod v_LengthOfPRBS;
    var octetstring v_Noctets := substr(tsc_RandomPRBS, v_Start, v_LengthOfPRBS - v_Start);

    while (lengthof(v_Noctets) < p_N) {
      v_Noctets := v_Noctets & tsc_RandomPRBS;
    }
    v_Noctets := substr(v_Noctets, 0, p_N);
    return v_Noctets;
  }

  //----------------------------------------------------------------------------

  type enumerated Gsm7BitPacking_Type { SMS_Packing, CBS_Packing, USSD_Packing };

  const integer tsc_Gsm7BitLookup[32..126][2] := {           /* ASCII to GSM 7 bit char conversion table
                                                                   Self indexing lookup table per ASCII integer value
                                                                   1st field - status
                                                                   0 => no change
                                                                   1 => basic table - no translation required
                                                                   2 => escape to ext table 23.038 6.2.1.1
                                                                   3 => char does not exist in gsm char table
                                                                   2nd field - translation integer value per 23.038 6.2.1/6.2.1.1
                                                                   range 0-127 & dummy entry 256 */
    {  0, 256 }, // 32 - space - no xlat
    {  0, 256 }, // 33 - "!" - no xlat
    {  0, 256 }, // 34 - """ - no xlat
    {  0, 256 }, // 35 - "#" - no xlat
    {  1,   2 }, // 36 - "$" - gsm 23.038 6.2.1 - 02
    {  0, 256 }, // 37 - "%" - no xlat
    {  0, 256 }, // 38 - "&" - no xlat
    {  0, 256 }, // 39 - "'" - no xlat
    {  0, 256 }, // 40 - "(" - no xlat
    {  0, 256 }, // 41 - ")" - no xlat
    {  0, 256 }, // 42 - "*" - no xlat
    {  0, 256 }, // 43 - "+" - no xlat
    {  0, 256 }, // 44 - "," - no xlat
    {  0, 256 }, // 45 - "-" - no xlat
    {  0, 256 }, // 46 - "." - no xlat
    {  0, 256 }, // 47 - "/" - no xlat
    {  0, 256 }, // 48 - "0" - no xlat
    {  0, 256 }, // 49 - "1" - no xlat
    {  0, 256 }, // 50 - "2" - no xlat
    {  0, 256 }, // 51 - "3" - no xlat
    {  0, 256 }, // 52 - "4" - no xlat
    {  0, 256 }, // 53 - "5" - no xlat
    {  0, 256 }, // 54 - "6" - no xlat
    {  0, 256 }, // 55 - "7" - no xlat
    {  0, 256 }, // 56 - "8" - no xlat
    {  0, 256 }, // 57 - "9" - no xlat
    {  0, 256 }, // 58 - ":" - no xlat
    {  0, 256 }, // 59 - ";" - no xlat
    {  0, 256 }, // 60 - "<" - no xlat
    {  0, 256 }, // 61 - "=" - no xlat
    {  0, 256 }, // 62 - ">" - no xlat
    {  0, 256 }, // 63 - "9" - no xlat
    {  1,   0 }, // 64 - "@" - gsm 23.038 6.2.1 - 00
    {  0, 256 }, // 65 - "A" - no xlat
    {  0, 256 }, // 66 - "B" - no xlat
    {  0, 256 }, // 67 - "C" - no xlat
    {  0, 256 }, // 68 - "D" - no xlat
    {  0, 256 }, // 69 - "E" - no xlat
    {  0, 256 }, // 70 - "F" - no xlat
    {  0, 256 }, // 71 - "G" - no xlat
    {  0, 256 }, // 72 - "H" - no xlat
    {  0, 256 }, // 73 - "I" - no xlat
    {  0, 256 }, // 74 - "J" - no xlat
    {  0, 256 }, // 75 - "K" - no xlat
    {  0, 256 }, // 76 - "L" - no xlat
    {  0, 256 }, // 77 - "M" - no xlat
    {  0, 256 }, // 78 - "N" - no xlat
    {  0, 256 }, // 79 - "0" - no xlat
    {  0, 256 }, // 80 - "P" - no xlat
    {  0, 256 }, // 81 - "Q" - no xlat
    {  0, 256 }, // 82 - "R" - no xlat
    {  0, 256 }, // 83 - "S" - no xlat
    {  0, 256 }, // 84 - "T" - no xlat
    {  0, 256 }, // 85 - "U" - no xlat
    {  0, 256 }, // 86 - "V" - no xlat
    {  0, 256 }, // 87 - "W" - no xlat
    {  0, 256 }, // 88 - "X" - no xlat
    {  0, 256 }, // 89 - "Y" - no xlat
    {  0, 256 }, // 90 - "Z" - no xlat
    {  2,  60 }, // 91 - "[" - gsm 23.038 6.2.1.1 ext. - 3C
    {  2,  47 }, // 92 - "\" - gsm 23.038 6.2.1.1 ext. - 2F
    {  2,  62 }, // 93 - "]" - gsm 23.038 6.2.1.1 ext. - 3E
    {  2,  20 }, // 94 - "^" - gsm 23.038 6.2.1.1 ext. - 14
    {  1,  17 }, // 95 - "_" - gsm 23.038 6.2.1 - 11
    {  3, 256 }, // 96 - "`" - char does not exist in gsm 23.038 6.2.1/6.2.1.1
    {  0, 256 }, // 97 - "a" - no xlat
    {  0, 256 }, // 98 - "b" - no xlat
    {  0, 256 }, // 99 - "c" - no xlat
    {  0, 256 }, // 100 - "d" - no xlat
    {  0, 256 }, // 101 - "e" - no xlat
    {  0, 256 }, // 102 - "f" - no xlat
    {  0, 256 }, // 103 - "g" - no xlat
    {  0, 256 }, // 104 - "h" - no xlat
    {  0, 256 }, // 105 - "i" - no xlat
    {  0, 256 }, // 106 - "j" - no xlat
    {  0, 256 }, // 107 - "k" - no xlat
    {  0, 256 }, // 108 - "l" - no xlat
    {  0, 256 }, // 109 - "m" - no xlat
    {  0, 256 }, // 110 - "n" - no xlat
    {  0, 256 }, // 111 - "o" - no xlat
    {  0, 256 }, // 112 - "p" - no xlat
    {  0, 256 }, // 113 - "q" - no xlat
    {  0, 256 }, // 114 - "r" - no xlat
    {  0, 256 }, // 115 - "s" - no xlat
    {  0, 256 }, // 116 - "t" - no xlat
    {  0, 256 }, // 117 - "u" - no xlat
    {  0, 256 }, // 118 - "v" - no xlat
    {  0, 256 }, // 119 - "w" - no xlat
    {  0, 256 }, // 120 - "x" - no xlat
    {  0, 256 }, // 121 - "y" - no xlat
    {  0, 256 }, // 122 - "z" - no xlat
    {  2,  40 }, // 123 - "{" - gsm 23.038 6.2.1.1 ext. - 28
    {  2,  64 }, // 124 - "|" - gsm 23.038 6.2.1.1 ext. - 40
    {  2,  41 }, // 125 - "}" - gsm 23.038 6.2.1.1 ext. - 29
    {  2,  61 }  // 126 - "~" - gsm 23.038 6.2.1.1 ext. - 3D
  };

  function fl_XlatAcsiiToGsm7Bit(octetstring p_AsciiOctetString) return octetstring
  {
    var octetstring v_GsmOctetString;
    var integer v_XlatStatus;
    var integer v_AsciiIndex;
    var integer i;
    var integer j := 0;

    for (i:=0; i<lengthof(p_AsciiOctetString); i:=i+1) {

      v_AsciiIndex := oct2int(p_AsciiOctetString[i]);
      v_XlatStatus := tsc_Gsm7BitLookup[v_AsciiIndex][0];
      select (v_XlatStatus) {
        case (0) {   // no Translation is needed - use ascii
          v_GsmOctetString[j] := int2oct(v_AsciiIndex, 1);
        }
        case (1) {   // xlat required using the basic table
          v_GsmOctetString[j] := int2oct(tsc_Gsm7BitLookup[v_AsciiIndex][1], 1);
        }
        case (2) {   // xlat required using the extended table
          v_GsmOctetString[j] := int2oct(27, 1); // insert ESC char
          j:=j+1;
          v_GsmOctetString[j] := int2oct(tsc_Gsm7BitLookup[v_AsciiIndex][1], 1);
        }
        case (3) {
          FatalError(__FILE__, __LINE__, "input character cannot be translated to GSM character");
        }
        case else {
          FatalError(__FILE__, __LINE__, "lookup table index out of range");
        }
      }
      j:= j+1;
    }
    return v_GsmOctetString;
  }

  /*
   * @desc      Packing of a 7 bit ASCII string to an 8 bit octet string (TS 23.038 cl. 6.1.2):
   *            SMS Packing (TS 23.038 cl. 6.1.2.1)
   *            CBS Packing (TS 23.038 cl. 6.1.2.2)
   *            USSD Packing (TS 23.038 cl. 6.1.2.3)
   * @param     p_Text
   * @param     p_Packing
   * @param     p_NumFillbits       (default value: 0)
   * @return    octetstring
   */
  function f_CharPacking_IA5toGsm7Bit(charstring p_Text,
                                      Gsm7BitPacking_Type p_Packing,
                                      integer p_NumFillbits := 0) return octetstring
  { /* @sic R5s130103 change 3: consideration of non alpha numeric characters sic@ */
    /* @sic R5s201329, R5s210441: p_NumFillbits - used e.g. for concatenated SMS, when the TP User Data has Data Header sic@ */
    var octetstring v_OctetString := char2oct(p_Text);   // "Hallo" -> '48616C6C6F'O
    var bitstring v_BitString := int2bit(0, p_NumFillbits);  // => fill bits are the rightmost bits of the first octet carrying the first (rightmost) bits of the first (leftmost) character of the message
    var bitstring v_Padding := ''B;
    var integer v_TextLength;
    var integer v_BitStringLength := p_NumFillbits;
    var integer v_IntValue;
    var integer v_NoOfOctets;
    var integer v_NoOfPaddingBits;
    var integer v_Index;
    var integer i;

    // convert ascii table to GSM 7 bit table
    v_OctetString := fl_XlatAcsiiToGsm7Bit(v_OctetString);                 //  @sic R5s130103 change 3 sic@
    v_TextLength := lengthof(v_OctetString);

    if (((p_Packing == SMS_Packing) and (v_TextLength > 160)) or           // a maximum of 160 characters for SMS  (i.e. 140 octets)
        ((p_Packing == CBS_Packing) and (v_TextLength > 93)) or            // a maximum of  93 characters for CBS  (i.e.  82 octets)
        ((p_Packing == USSD_Packing) and (v_TextLength > 182))) {          // a maximum of 182 characters for USSD (i.e. 160 octets)
      FatalError(__FILE__, __LINE__, "input string is too long");
    }

    for (i:=0; i<v_TextLength; i:=i+1) {
      v_IntValue := oct2int(v_OctetString[i]);
      v_BitString := int2bit(v_IntValue, 7) & v_BitString;  // concat 7 bits only
      v_BitStringLength := v_BitStringLength + 7;
    }
    // add padding:
    v_NoOfOctets := (v_BitStringLength + 7) / 8;
    v_NoOfPaddingBits := (v_NoOfOctets * 8) - v_BitStringLength;
    if (v_NoOfPaddingBits > 0) {
      if ((p_Packing == USSD_Packing) and (v_NoOfPaddingBits == 7)) {
        v_Padding := '0001101'B;                     // use <CR> instead of the @ character; see TS 23.038 cl. 6.1.2.3.1
      } else {
        v_Padding := int2bit(0, v_NoOfPaddingBits);  // 1..7 padding bits, all 0
      }
    }
    v_BitString := v_Padding & v_BitString;

    // convert bitstring back to octetstring: the first character is at the end of the bitstring
    // => we need to take the octets from the end of the bitstring
    v_OctetString := ''O;
    for (i:=0; i < v_NoOfOctets; i:=i+1) {
      v_Index := (v_NoOfOctets - (i+1)) * 8;    // get start index of the next octet
      v_OctetString[i] := bit2oct(substr(v_BitString, v_Index, 8));
    }
    return v_OctetString;
  }

  function f_CharPacking_IA5toBCD(charstring p_ASCII_String) return octetstring
  { /* Packed BCD coding with "swaping of nibbles" as required e.g. for encoding of called and calling party numbers in NAS messages (e.g. TS 24.004 cl. 10.5.4.7 and 10.5.4.9);
       when the length of the input string is odd 'F' is aded as padding:
       "0613454120"  -> '6031541402'O       - even number of digits
       "06134541209" -> '6031541402F9'O     - odd number of digits (padding)
       "A6134541209" -> error */
    var integer i;
    var charstring v_BcdString;
    var integer v_Length := lengthof(p_ASCII_String);
    var charstring v_ASCII_String := p_ASCII_String;

    // check input string
    for (i := 0; i < v_Length; i := i+1) {
      if (not match(p_ASCII_String[i], pattern "[0-9]")) {
        FatalError(__FILE__, __LINE__, "invalid character for BCD string");
      }
    }

    // add padding (if needed)
    if (v_Length mod 2 != 0) {
      v_ASCII_String := v_ASCII_String & "F";
    }

    // swap digits
    for (i := 0; i < v_Length; i := i+2) {
      v_BcdString[i]   := v_ASCII_String[i+1];
      v_BcdString[i+1] := v_ASCII_String[i];
    }

    return str2oct(v_BcdString);
  }

  //----------------------------------------------------------------------------

  function f_BitstringReplaceMSB(bitstring p_Bitstring,
                                 B1_Type p_NewMSB) return bitstring
  {
    return replace(p_Bitstring, 0, 1, p_NewMSB);
  }

  //----------------------------------------------------------------------------

  function f_Bitstring_BitIsSet(bitstring p_Bitstring,
                                integer p_Index) return boolean
  {
    if (p_Index >= lengthof(p_Bitstring)) {
      FatalError(__FILE__, __LINE__, "invalid bit position");
    }
    return (substr(p_Bitstring, p_Index, 1) == '1'B);
  }

  function f_Bitstring_LeastSignificantBits(bitstring p_Bitstring,
                                            integer p_NoOfBis) return bitstring
  {
    var integer v_Length := lengthof(p_Bitstring);
    if (p_NoOfBis > v_Length) {
      FatalError(__FILE__, __LINE__, "invalid length");
    }
    return substr(p_Bitstring, v_Length - p_NoOfBis, p_NoOfBis);
  }

  function f_BitstringTemplate_SetBit(template (present) bitstring p_Bitstring,
                                      integer p_Position,
                                      template (present) B1_Type p_Bit) return template (present) bitstring
  { /* ES 201 873-1 clause 15.6.1 does not allow index notation */
    /* p_Bitstring needs to be a bitstring with well-defined length (i.e. allowing lengthof(p_Bitstring)) */
    var bitstring v_Substring1;
    var bitstring v_Substring2;
    var integer v_Length := lengthof(p_Bitstring);

    if (p_Position >= v_Length) {
      FatalError(__FILE__, __LINE__, "out of range");
    }
    v_Substring1 := substr(p_Bitstring, 0, p_Position);
    v_Substring2 := substr(p_Bitstring, p_Position + 1, v_Length - p_Position - 1);

    return v_Substring1 & valueof(p_Bit) & v_Substring2;
  }

  //----------------------------------------------------------------------------
  // Moved here because now needed in Authentication_Init (i.e. GERAN and UTRAN PTCs too)
  const integer tsc_KDF_HMAC_SHA_256 := 1;      /* @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_IRAT, POS, SSNITZ, UTRAN) */
  const integer tsc_KDF_Spare3 := 4;            /* @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_IRAT, POS, SSNITZ, UTRAN) */
  type integer KDF_Type ( tsc_KDF_HMAC_SHA_256 .. tsc_KDF_Spare3 );     /* @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_IRAT, POS, UTRAN) */

  external function fx_KeyDerivationFunction(KDF_Type  p_KDF,
                                             bitstring p_Key, //@sic R5-155058 sic@
                                             octetstring p_String) return B256_Type;
  /* External function to hashing function with algorithm as defined in 33.401;
     SHA-256 encoding algorithm used as KEY Description Function
     @status    APPROVED (LTE) */

  external function fx_CalculateFCS32 (bitstring p_TMSI) return B32_Type;  /* Cyclic Redundancy Check calculation according to ITU-T Recommendation V.42 of CRC-32 Algorithm @sic R5-172046 sic@ */

  //----------------------------------------------------------------------------
  /* system time acc. to default C library (see time.h) */

  type record Struct_tm_Type {  /* TTCN-3 equivalent for the "struct tm" as defined on C standard library (time.h or ctime.h for C or C++) */
    integer tm_sec,             /* seconds after the minute    0..61 (tm_sec is generally 0-59. Extra range to accommodate for leap seconds in certain systems) */
    integer tm_min,             /* minutes after the hour      0..59   */
    integer tm_hour,            /* hours since midnight        0..23   */
    integer tm_mday,            /* day of the month            1..31   */
    integer tm_mon,             /* months since January        0..11   */
    integer tm_year,            /* years since 1900                    */
    integer tm_wday,            /* days since Sunday           0..6    */
    integer tm_yday,            /* days since January 1        0..365  */
    integer tm_isdst            /* Daylight Saving Time flag           */
  };

  external function fx_GetSystemTime(out Struct_tm_Type p_Struct_tm,    /* p_Struct_tm returns local system time;
                                                                         * C implementation:
                                                                         *         time_t v_Now = time(NULL);
                                                                         *         struct tm *v_Tm = localtime(&v_Now);
                                                                         */
                                     out integer p_TimezoneInfo);       /* p_TimezoneInfo returns the difference (in seconds) between the UTC time (GMT) and the local time;
                                                                         * C implementation:
                                                                         *         int timezone = (int)difftime(mktime(gmtime(&v_Now)), v_Now);
                                                                         * NOTE: p_TimezoneInfo does not consider daylight saving e.g. it is always 3600 for CET independent of summer/winter
                                                                         */





  //----------------------------------------------------------------------------
  /*
   * @desc      returns integer formated as "%02d"
   * @param     p_Value
   * @return    charstring
   * @status    APPROVED (IMS)
   */
  function fl_FormatIntegerAsTwoDigits(UInt_Type p_Value) return charstring
  {
    var UInt_Type v_Value := p_Value mod 100;
    var charstring v_String := int2str(v_Value);

    if (v_Value < 10) {
      v_String := "0" & v_String;
    }
    return v_String;
  }

  /*
   * @desc      return HTTP Date/Time formatted according to RFC 2616 cl. 3.3.1 and RFC 822 cl. 5.1 (obsoleted by RFC 2822, obsoleted by RFC 5322)
   * @param     p_LocalTime
   * @param     p_TimezoneSeconds
   * @return    charstring
   * @status    APPROVED (IMS)
   */
  function f_HTTP_FormatHttpDate(Struct_tm_Type p_LocalTime,
                                 integer p_TimezoneSeconds) return charstring
  {
    const CharStringList_Type tsc_Month := { "Jan", "Feb","Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    const CharStringList_Type tsc_WDay := { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    var charstring v_Year     := int2str(p_LocalTime.tm_year + 1900);
    var charstring v_Month    := tsc_Month[p_LocalTime.tm_mon];
    var charstring v_WDay     := tsc_WDay[p_LocalTime.tm_wday];
    var charstring v_MDay     := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_mday);
    var charstring v_Hour     := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_hour);
    var charstring v_Minute   := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_min);
    var charstring v_Second   := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_sec);
    var integer v_TimezoneSeconds := p_TimezoneSeconds;
    var charstring v_TimezoneSign;
    var charstring v_TimezoneHours;
    var charstring v_TimezoneMinutes;

    if (p_LocalTime.tm_isdst > 0) {     // see f_BCD_TimestampWithTimezone
      v_TimezoneSeconds := v_TimezoneSeconds + 3600;
    }
    if (v_TimezoneSeconds < 0) {
      v_TimezoneSeconds := -v_TimezoneSeconds;
      v_TimezoneSign := "-";
    } else {
      v_TimezoneSign := "+";
    }
    v_TimezoneHours := fl_FormatIntegerAsTwoDigits(v_TimezoneSeconds / 3600);
    v_TimezoneMinutes := fl_FormatIntegerAsTwoDigits((v_TimezoneSeconds mod 3600) / 60);

    return v_WDay & ", " & v_MDay & " " & v_Month & " " & v_Year & " " & v_Hour & ":" & v_Minute & ":" & v_Second &  " " & v_TimezoneSign & v_TimezoneHours & v_TimezoneMinutes;
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      format date and time acc. to UTC
   * @param     p_LocalTime
   * @param     p_TimezoneSeconds   (default value: omit)
   * @return    charstring
   * @status    APPROVED (IMS)
   */
  function f_UTC_FormatDateTime(Struct_tm_Type p_LocalTime,
                                template (omit) integer p_TimezoneSeconds := omit) return charstring
  {
    var charstring v_Year     := int2str(p_LocalTime.tm_year + 1900);
    var charstring v_Month    := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_mon + 1);   // @sic R5s201156: p_LocalTime.tm_mon + 1 sic@
    var charstring v_MDay     := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_mday);
    var charstring v_Hour     := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_hour);
    var charstring v_Minute   := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_min);
    var charstring v_Second   := fl_FormatIntegerAsTwoDigits(p_LocalTime.tm_sec);
    var charstring v_Timezone := "";
    var charstring v_Sign;
    var integer v_TimezoneSeconds;
    var integer v_TimezoneMinutes;

    if (isvalue(p_TimezoneSeconds)) {                                                   // @sic R5s201156 sic@
      v_TimezoneSeconds := valueof(p_TimezoneSeconds);
      if (v_TimezoneSeconds > 0) {
        v_Sign := "-";
      } else {
        v_Sign := "+";
        v_TimezoneSeconds := - v_TimezoneSeconds;
      }
      v_TimezoneMinutes := v_TimezoneSeconds / 60;
      v_Timezone := v_Sign & fl_FormatIntegerAsTwoDigits(v_TimezoneMinutes / 60) & ":" & fl_FormatIntegerAsTwoDigits(v_TimezoneMinutes mod 60);
    }
    return v_Year & "-" & v_Month & "-" & v_MDay & "T" & v_Hour & ":" & v_Minute & ":" & v_Second & v_Timezone;
  }

  /*
   * @desc      return timestamp (current system time) according to ISO 8601
   * @return    charstring
   */
  function f_UTC_Timestamp() return charstring
  {
    var Struct_tm_Type v_LocalTime;
    var integer v_TimezoneSeconds;

    fx_GetSystemTime(v_LocalTime, v_TimezoneSeconds);
    return f_UTC_FormatDateTime(v_LocalTime, v_TimezoneSeconds);
  }

  /*
   * @desc      auxiliary function for f_BCD_TimestampWithTimezone
   * @param     p_Val
   * @return    H2_Type
   */
  function f_SwappedNibbles(integer p_Val) return H2_Type
  {
    var integer v_LowNibble  := p_Val mod 10;
    var integer v_HighNibble := (p_Val / 10) mod 10;

    return int2hex(v_LowNibble, 1) & int2hex(v_HighNibble, 1);
  }

  /*
   * @desc      returns the timestamp as e.g. used as ServiceCentreTimeStamp for SMS with current time
   *            (see e.g. calculation of the TP Service Centre Time Stamp acc. to TS 23.040 cl. 9.2.3.11)
   *            Example:
   *            2002 April 18, 15:32:46, timezone=4
   *            f_BCD_TimestampWithTimezone returns 20408151236440
   * @return    H14_Type
   */
  function f_BCD_TimestampWithTimezone() return H14_Type
  { /* @sic R5-1307270: common function to provide timestamp for MDT test cases too sic@ */
    var Struct_tm_Type v_LocalTime;
    var integer v_TimezoneSeconds;
    var integer v_TimezoneVal;
    var integer v_SignVal := 0;  // positive value per default
    var H2_Type v_Year;
    var H2_Type v_Month;
    var H2_Type v_Day;
    var H2_Type v_Hour;
    var H2_Type v_Minute;
    var H2_Type v_Second;
    var H2_Type v_Timezone;

    fx_GetSystemTime(v_LocalTime, v_TimezoneSeconds);

    v_Year      := f_SwappedNibbles(v_LocalTime.tm_year + 1900);     /* acc. to definition of struct tm */
    v_Month     := f_SwappedNibbles(v_LocalTime.tm_mon + 1);         /* acc. to definition of struct tm */
    v_Day       := f_SwappedNibbles(v_LocalTime.tm_mday);
    v_Hour      := f_SwappedNibbles(v_LocalTime.tm_hour);
    v_Minute    := f_SwappedNibbles(v_LocalTime.tm_min mod 60);      /* v_LocalTime.tm_min can be 0..61 on some systems */
    v_Second    := f_SwappedNibbles(v_LocalTime.tm_sec);

    /* Calculation of the timezone (-> 23.040): */
    if (v_LocalTime.tm_isdst > 0) {                 /* The value contained in the Time Zone field must take into account daylight saving time, such that when the sending entity changes from regular
                                                       (winter) time to daylight saving (summer) time, there is a change to the value in the Time Zone field,
                                                       for example in the UK the winter setting is 00000000 and the summer setting is 01000000. */
      v_TimezoneSeconds := v_TimezoneSeconds + 3600;
    }

    if (v_TimezoneSeconds < 0) {
      v_TimezoneSeconds := -v_TimezoneSeconds;
      v_SignVal := 128;                             /* In the first of the two semi octets, the first bit (bit 3 of the seventh octet of the TP Service Centre Time Stamp field)
                                                       represents the algebraic sign of this difference (0: positive, 1: negative) */
    }
    v_TimezoneVal := v_TimezoneSeconds / (60 * 15); /* The Time Zone indicates the difference, expressed in quarters of an hour, between the local time and GMT. */
    v_TimezoneVal := v_TimezoneVal mod 128;         /* ... just to be sure */
    v_TimezoneVal := v_TimezoneVal + v_SignVal;     /* set the upper bit */

    v_Timezone  := f_SwappedNibbles(v_TimezoneVal);

    return v_Year & v_Month & v_Day & v_Hour & v_Minute & v_Second & v_Timezone;
  }

  /*
   * @desc      wrapper function to strip the timezone (e.g. for 'AbsoluteTimeInfo' acc. to 36.331 cl. 6.3.6)
   * @return    H12_Type
   * @status
   */
  function f_BCD_TimestampWithoutTimezone() return H12_Type
  {
    var H14_Type v_TimestampWithTimezone := f_BCD_TimestampWithTimezone();
    return substr(v_TimestampWithTimezone, 0, 12);
  }

  /*
   * @desc      wrapper function to convert f_BCD_TimestampWithoutTimezone() to bitstring as needed for MDT
   * @return    B48_Type
   * @status
   */

  function f_MDT_GetAbsolute_TimeStamp() return B48_Type
  {
    return hex2bit(f_BCD_TimestampWithoutTimezone());
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      similar to mktime but considering the "TimezoneInfo" as e.g. returned by fx_GetSystemTime
   * @param     p_TM
   * @param     p_TimezoneDelta
   * @return    integer
   * @status    APPROVED (MCX)
   */
  function f_UTC_MKTime(Struct_tm_Type p_TM,
                        integer p_TimezoneDelta) return integer
  {
    var integer v_Seconds;
    var integer v_MonthsSinceJanuary;
    var integer v_CurrentMonth;
    var integer v_Days := 0;
    var boolean v_CurrentYearIsLeapYear := false;

    if (p_TM.tm_year > 0) {                               // 1900 has been no leap year in contrast to 2000, 2100 and beyond not considered
      v_CurrentYearIsLeapYear := ((p_TM.tm_year mod 4) == 0);
      v_Days := p_TM.tm_year * 365;
      v_Days := v_Days + ((p_TM.tm_year - 1) / 4);        // every 4th year is a leap year; current year is considered in the calculation for the month
    }

    for (v_MonthsSinceJanuary := 0; v_MonthsSinceJanuary < p_TM.tm_mon; v_MonthsSinceJanuary := v_MonthsSinceJanuary + 1) {
      v_CurrentMonth := v_MonthsSinceJanuary + 1;
      select (v_CurrentMonth) {
        case (2) {
          v_Days := v_Days + 28;
          if (v_CurrentYearIsLeapYear) {
            v_Days := v_Days + 1;
          }
        }
        case (4, 6, 9, 11) {
          v_Days := v_Days + 30;
        }
        case else {
          v_Days := v_Days + 31;
        }
      }
    }
    v_Days := v_Days + (p_TM.tm_mday - 1);              // "-1" as tm_mday is 1..31
    v_Seconds := (((((v_Days * 24) + p_TM.tm_hour) * 60) + p_TM.tm_min) * 60) + p_TM.tm_sec + p_TimezoneDelta;
    if (p_TM.tm_isdst > 0) {
      v_Seconds := v_Seconds - 3600;
    }
    return v_Seconds;
  }

  /*
   * @desc      Return the upper part of the NTP timestamp acc. to RFC 958 (i.e. the seconds since january 1st 1900 UTC)
   * @return    integer
   * @status    APPROVED (MCX)
   */
  function f_UTC_TimestampSeconds() return integer
  {
    var Struct_tm_Type v_TM;
    var integer v_TimezoneDelta;

    fx_GetSystemTime(v_TM, v_TimezoneDelta);

    return f_UTC_MKTime(v_TM, v_TimezoneDelta);
  }

  /*
   * @desc      seconds since 00:00:00 UTC on 1 January 1970 UTC (GMT)
   * @return    integer
   * @status    APPROVED (MCX)
   */
  function f_UnixEpoch_TimestampSeconds() return integer
  {
    return f_UTC_TimestampSeconds() - 2208988800;
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      To convert UTRAN cell ID acc to 34.123-3 clause 8.5
   * @param     p_CellId - enumerated type
   * @return    integer
   * @status
   */
  function f_UtranCellId2Int(UTRAN_CellId_Type p_CellId) return integer
  {  // @sic R5s130195 Baseline moving to rel-11: UTRAN cellID enhanced sic@
    var integer v_CellId := enum2int(p_CellId);

    // @sic R5-133563: added utran34_CellA/B/C... for 34.123-1 NAS tc sic@
    if (v_CellId >= 2000)  {
      v_CellId := v_CellId - 2000;
    } else if (v_CellId >= 1000)  {
      v_CellId := v_CellId - 1000;
    }
    return v_CellId;
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      check that the result string starts with specific sub-string
   * @param     p_SourceString
   * @param     p_StartString
   * @return    boolean
   */
  function f_CheckStringStartWith(charstring p_SourceString,
                                  charstring p_StartString)
    return boolean
  {
    var integer v_Length := lengthof(p_StartString);
    var charstring v_SubStr;
    var boolean v_Result := false;

    if (v_Length <= lengthof(p_SourceString)) {
      v_SubStr := substr(p_SourceString, 0, v_Length);
      v_Result := (v_SubStr == p_StartString);
    }
    return v_Result;
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      Return TRUE if the band is an FDD band or false otherwise
   *            If the band indication is a placeholder for an ext. band (maxFBI=64) this means as well an FDD band
   *            as all ext. bands are FDD bands
   * @param     p_FrequencyBand
   * @return    boolean
   */
  function f_EUTRA_FrequencyBandIsFDD(integer p_FrequencyBand) return boolean
  { //@sic R5s160134 sic@
    return (p_FrequencyBand < 33 or p_FrequencyBand >= 64); //@sic R5-162796, R5-193997 sic@
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      calculation of DRB_Identity associated to EpsBearerId
   * @param     p_EpsBearerId
   * @return    integer
   * @status    APPROVED (IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, POS)
   */
  function f_EUTRA_NB_EpsBearerAssociatedDRB(HalfOctet_Type p_EpsBearerId) return integer
  { /* @sic R5s141351 change 5: returns integer instead of DRB_Identity sic@ */
    return (hex2int(p_EpsBearerId) - 4);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      return value for given name from Name-Value list or omit if there is no entry for the given name
   * @param     p_NameValueList
   * @param     p_Name
   * @return    charstring
   */
  function f_NameValueList_Get(NameValueList_Type p_NameValueList,
                               charstring p_Name) return template (omit) charstring
  {
    var integer i;

    for (i := 0; i < lengthof(p_NameValueList); i := i + 1) {
      if (p_NameValueList[i].Name == p_Name) {
        return p_NameValueList[i].Value;
      }
    }
    return omit;
  }
} with {
  encode "RAW"
}
