diff options
author | Harald Welte <laforge@gnumonks.org> | 2017-12-24 20:38:20 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2017-12-25 00:00:58 +0100 |
commit | c676c68de6d58dbff24b5e6929d740f513e05dd4 (patch) | |
tree | 39318571e681af490e396ea6f94b6f1e6a66b589 | |
parent | 38b2a10e0b28f2367a4b894a5ff5a51b06f434fa (diff) |
Add 3GPP TS 25.415 IuUP encoder/decoder
Change-Id: Ie04438d8ec2b796e9e56b1937fa024a5299457dd
-rw-r--r-- | library/IuUP_Emulation.ttcn | 137 | ||||
-rw-r--r-- | library/IuUP_EncDec.cc | 250 | ||||
-rw-r--r-- | library/IuUP_Types.ttcn | 338 |
3 files changed, 725 insertions, 0 deletions
diff --git a/library/IuUP_Emulation.ttcn b/library/IuUP_Emulation.ttcn new file mode 100644 index 00000000..ec25e49e --- /dev/null +++ b/library/IuUP_Emulation.ttcn @@ -0,0 +1,137 @@ +module IuUP_Emulation { + +import from Osmocom_Types all; +import from IuUP_Types all; + + +type record IuUP_RabFlowCombination { + IuUP_RFCI rfci, + /* number of bits per sub-flow */ + RecOfU8 sub_flow_bits, + /* IPTI value in number of ITIs for the corresponding RFCI */ + uint8_t ipti +}; + +template (value) IuUP_RabFlowCombination t_IuUP_RFC(IuUP_RFCI rfci, RecOfU8 subflow_bits, uint8_t ipti) := { + rfci := rfci, + sub_flow_bits := subflow_bits, + ipti := ipti +} + +template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_12_2(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {81, 103, 60}, 1); +template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_SID(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {34, 0, 0}, 7); + +type record IuUP_Config { + /* actively send INIT (true) or only passively respond (false) */ + boolean active_init, + boolean data_pdu_type_0, + /* RAB Flow Combinations */ + record of IuUP_RabFlowCombination rab_flow_combs +}; + +type enumerated IuUP_Em_State { + ST_INIT, + ST_DATA_TRANSFER_READY +}; + + + +type record IuUP_Entity { + IuUP_Config cfg, + IuUP_Em_State state, + IuUP_FrameNr tx_next_frame_nr, + IuUP_FrameNr rx_last_frame_nr optional, + IuUP_PDU pending_tx_pdu optional +}; + +template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := { + cfg := { + active_init := act_init, + data_pdu_type_0 := true, + rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1) } + }, + state := ST_INIT, + tx_next_frame_nr := 0, + rx_last_frame_nr := omit, + pending_tx_pdu := omit +} + + +function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring { + var IuUP_PDU pdu := dec_IuUP_PDU(inp); + if (ischosen(pdu.type_0)) { + if (st.cfg.data_pdu_type_0) { + /* FIXME: check header / CRC */ + st.rx_last_frame_nr := pdu.type_0.frame_nr; + return pdu.type_0.payload; + } else { + setverdict(fail, "PDU Type 0 received but 1 configured"); + } + } else if (ischosen(pdu.type_1)) { + if (st.cfg.data_pdu_type_0 == false) { + /* FIXME: check header / CRC */ + st.rx_last_frame_nr := pdu.type_1.frame_nr; + return pdu.type_1.payload; + } else { + setverdict(fail, "PDU Type 1 received but 0 configured"); + } + } else if (ischosen(pdu.type_14)) { + if (match(pdu, tr_IuUP_INIT)) { + if (st.cfg.active_init == true) { + setverdict(fail, "INIT received in ACTIVE role"); + } else { + /* store an INIT_ACK to be transmitted later */ + st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr, + pdu.type_14.iuup_version)); + } + } else if (match(pdu, tr_IuUP_INIT_ACK)) { + if (st.cfg.active_init == true) { + log("IuUP INIT_ACK Received"); + st.state := ST_DATA_TRANSFER_READY; + } else { + setverdict(fail, "INIT_ACK received in PASSIVE role"); + } + } + return ''O; + } else { + setverdict(fail, "Impossible IuUP PDU decoded from ", inp); + } + self.stop; +} + +function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring { + var IuUP_PDU pdu; + select (st.state) { + case (ST_INIT) { + if (st.cfg.active_init) { + /* send INIT */ + pdu := valueof(ts_IuUP_INIT('160051673C01270000820000001710000100'O)); + } else { + /* wait for INIT */ + if (isvalue(st.pending_tx_pdu)) { + /* we're waiting to transmit the INIT_ACK in response to an + * init (passive) */ + pdu := st.pending_tx_pdu; + st.pending_tx_pdu := omit; + st.state := ST_DATA_TRANSFER_READY; + } + } + } + case (ST_DATA_TRANSFER_READY) { + if (st.cfg.data_pdu_type_0) { + pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload)); + } else { + pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload)); + } + st.tx_next_frame_nr := st.tx_next_frame_nr + 1; + } + } + if (isvalue(pdu)) { + return f_enc_IuUP_PDU(pdu); + } else { + return ''O; + } +} + + +} diff --git a/library/IuUP_EncDec.cc b/library/IuUP_EncDec.cc new file mode 100644 index 00000000..81742e8a --- /dev/null +++ b/library/IuUP_EncDec.cc @@ -0,0 +1,250 @@ + +#include "Octetstring.hh" +#include "Error.hh" +#include "Logger.hh" + +#include "IuUP_Types.hh" + +#include <stdint.h> + +extern "C" { + +typedef uint8_t ubit_t; +typedef uint8_t pbit_t; + +static int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits) +{ + unsigned int i; + ubit_t *cur = out; + ubit_t *limit = out + num_bits; + + for (i = 0; i < (num_bits/8)+1; i++) { + pbit_t byte = in[i]; + *cur++ = (byte >> 7) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 6) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 5) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 4) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 3) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 2) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 1) & 1; + if (cur >= limit) + break; + *cur++ = (byte >> 0) & 1; + if (cur >= limit) + break; + } + return cur - out; +} + + +struct osmo_crc8gen_code { + int bits; /*!< Actual number of bits of the CRC */ + uint8_t poly; /*!< Polynom (normal representation, MSB omitted */ + uint8_t init; /*!< Initialization value of the CRC state */ + uint8_t remainder; /*!< Remainder of the CRC (final XOR) */ +}; + +static uint8_t +osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code, + const ubit_t *in, int len) +{ + const uint8_t poly = code->poly; + uint8_t crc = code->init; + int i, n = code->bits-1; + + for (i=0; i<len; i++) { + uint8_t bit = in[i] & 1; + crc ^= (bit << n); + if (crc & ((uint8_t)1 << n)) { + crc <<= 1; + crc ^= poly; + } else { + crc <<= 1; + } + crc &= ((uint8_t)1 << code->bits) - 1; + } + + crc ^= code->remainder; + + return crc; +} + +struct osmo_crc16gen_code { + int bits; /*!< Actual number of bits of the CRC */ + uint16_t poly; /*!< Polynom (normal representation, MSB omitted */ + uint16_t init; /*!< Initialization value of the CRC state */ + uint16_t remainder; /*!< Remainder of the CRC (final XOR) */ +}; + +static uint16_t +osmo_crc16gen_compute_bits(const struct osmo_crc16gen_code *code, + const ubit_t *in, int len) +{ + const uint16_t poly = code->poly; + uint16_t crc = code->init; + int i, n = code->bits-1; + + for (i=0; i<len; i++) { + uint16_t bit = in[i] & 1; + crc ^= (bit << n); + if (crc & ((uint16_t)1 << n)) { + crc <<= 1; + crc ^= poly; + } else { + crc <<= 1; + } + crc &= ((uint16_t)1 << code->bits) - 1; + } + + crc ^= code->remainder; + + return crc; +} + +} + + +static const struct osmo_crc8gen_code iuup_hdr_crc_code = { + .bits = 6, + .poly = 47, + .init = 0, + .remainder = 0, +}; + +static const struct osmo_crc16gen_code iuup_data_crc_code = { + .bits = 10, + .poly = 563, + .init = 0, + .remainder = 0, +}; + +static int iuup_get_payload_offset(const uint8_t *iuup_pdu) +{ + uint8_t pdu_type = iuup_pdu[0] >> 4; + switch (pdu_type) { + case 0: + case 14: + return 4; + case 1: + return 3; + default: + return -1; + } +} + +int osmo_iuup_compute_payload_crc(const uint8_t *iuup_pdu, unsigned int pdu_len) +{ + ubit_t buf[1024*8]; + uint8_t pdu_type; + int offset, payload_len_bytes; + + if (pdu_len < 1) + return -1; + + pdu_type = iuup_pdu[0] >> 4; + + /* Type 1 has no CRC */ + if (pdu_type == 1) + return 0; + + offset = iuup_get_payload_offset(iuup_pdu); + if (offset < 0) + return offset; + + if (pdu_len < (unsigned int)offset) + return -1; + + payload_len_bytes = pdu_len - offset; + osmo_pbit2ubit(buf, iuup_pdu+offset, payload_len_bytes*8); + return osmo_crc16gen_compute_bits(&iuup_data_crc_code, buf, payload_len_bytes*8); +} + +int osmo_iuup_compute_header_crc(const uint8_t *iuup_pdu, unsigned int pdu_len) +{ + ubit_t buf[2*8]; + + if (pdu_len < 2) + return -1; + + osmo_pbit2ubit(buf, iuup_pdu, 2*8); + return osmo_crc8gen_compute_bits(&iuup_hdr_crc_code, buf, 2*8); +} +/* IuUP CRC Implementation */ + +/* (C) 2017 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace IuUP__Types { + + +INTEGER f__IuUP__compute__crc__payload(OCTETSTRING const &in) +{ + int crc_calc; + const unsigned char *data = (const unsigned char *)in; + int len = in.lengthof(); + + crc_calc = osmo_iuup_compute_payload_crc(data, len); + + return INTEGER(crc_calc); +} + +INTEGER f__IuUP__compute__crc__header(OCTETSTRING const &in) +{ + int crc_calc; + const unsigned char *data = (const unsigned char *)in; + int len = in.lengthof(); + + crc_calc = osmo_iuup_compute_header_crc(data, len); + + return INTEGER(crc_calc); +} + +OCTETSTRING f__enc__IuUP__PDU(const IuUP__PDU& pdu) +{ + TTCN_Buffer buf; + int crc_hdr, crc_payload; + uint8_t in[2]; + pdu.encode(IuUP__PDU_descr_, buf, TTCN_EncDec::CT_RAW); + OCTETSTRING ret_val(buf.get_len(), buf.get_data()); + + crc_hdr = osmo_iuup_compute_header_crc(buf.get_data(), buf.get_len()); + crc_payload = osmo_iuup_compute_payload_crc(buf.get_data(), buf.get_len()); + in[0] = (crc_hdr & 0x3f) << 2; + in[0] |= (crc_payload & 0x3ff) >> 8; + in[1] = crc_payload & 0xff; + OCTETSTRING CHECKSUM(2, in); + + ret_val = substr(ret_val, 0, 2) + CHECKSUM + substr(ret_val, 4, ret_val.lengthof()-4); + + return ret_val; +} + +} diff --git a/library/IuUP_Types.ttcn b/library/IuUP_Types.ttcn new file mode 100644 index 00000000..933b64fd --- /dev/null +++ b/library/IuUP_Types.ttcn @@ -0,0 +1,338 @@ +module IuUP_Types { + +import from Osmocom_Types all; +import from General_Types all; + +/* See TS 25.415 6.6.3.1 */ +type uint4_t IuUP_PDU_Type; + +/* See TS 25.415 6.6.3.2 */ +type enumerated IuUP_AckNack { + IuUP_ACKNACK_CTRL (0), + IuUP_ACKNACK_ACK (1), + IuUP_ACKNACK_NACK (2), + IuUP_ACKNACK_RESERVED (3) +} with { variant "FIELDLENGTH(2)" }; + +/* See TS 25.415 6.6.3.3 */ +type uint4_t IuUP_FrameNr; + +/* See TS 25.415 6.6.3.5 */ +type enumerated IuUP_FQC { + IuUP_FQC_GOOD (0), + IuUP_FQC_BAD (1), + IuUP_FQC_BAD_RADIO (2), + IuUP_FQC_SPARE (3) +} with { variant "FIELDLENGTH(2)" }; + +/* See TS 25.415 6.6.3.6 */ +type uint6_t IuUP_RFCI; + +/* See TS 25.415 6.6.3.7 */ +type enumerated IuUP_ProcedureIndicator { + IuUP_PRI_INITIALIZATION (0), + IuUP_PRI_RATE_CONTROL (1), + IuUP_PRI_TIME_ALIGNMENT (2), + IuUP_PRI_ERROR_EVENT (3) + /* reserved */ +} with { variant "FIELDLENGTH(4)" }; + +/* See TS 25.415 6.6.3.13 */ +type uint6_t IuUP_NumOfRfciInd; + +/* See TS 25.415 6.6.3.15 */ +type enumerated IuUP_ErrorDistance { + IuUP_ERR_DIST_LOCAL (0), + IuUP_ERR_DIST_FIRST_FW (1), + IuUP_ERR_DIST_SECOND_FW (2), + IuUP_ERR_DIST_RESERVED (3) +} with { variant "FIELDLENGTH(2)" }; + +/* See TS 25.415 6.6.3.16 */ +type enumerated IuUP_ErrorCause { + /* Syntactical protocol errors */ + IuUP_CAUSE_CRC_ERROR_HEADER (0), + IuUP_CAUSE_CRC_ERROR_PAYLOAD (1), + IuUP_CAUSE_UNEXP_FRAME_NR (2), + IuUP_CAUSE_FRAME_LOSS (3), + IuUP_CAUSE_PDU_TYPE_UNKNOWN (4), + IuUP_CAUSE_UNKNOWN_PROCEDURE (5), + IuUP_CAUSE_UNKNOWN_RES_VAL (6), + IuUP_CAUSE_UNKNOWN_FIELD (7), + IuUP_CAUSE_FRAME_TOO_SHORT (8), + IuUP_CAUSE_MISSING_FIELD (9), + /* Semantical protocol errors */ + IuUP_CAUSE_UNEXPECTED_PDU_TYPE (16), + IuUP_CAUSE_UNEXPECTED_PROCEDURE (18), + IuUP_CAUSE_UNEXPECTED_RFCI (19), + IuUP_CAUSE_UNEXPECTED_VALUE (20), + /* Other Errors */ + IuUP_CAUSE_INIT_FAIL (42), + IuUP_CAUSE_INIT_FAIL_NET_TMR_EXP (43), + IuUP_CAUSE_INIT_FAIL_FERR_REP_NACK (44), + IuUP_CAUSE_RATE_CONTROL_FAIL (45), + IuUP_CAUSE_ERROR_EVENT_FAIL (46), + IuUP_CAUSE_TIME_ALIGN_NOTSUPP (47), + IuUP_CAUSE_REQ_ALIGN_NOTPOSS (48), + IuUP_CAUSE_IU_UP_VERS_NOTSUPP (49) +} with { variant "FIELDLENGTH(6)" }; + +/* See TS 25.415 6.6.3.18 */ +type uint8_t IuUP_TimeAlignment; + + +/* See TS 25.415 6.6.2.1 */ +type record IuUP_PDU_Type_0 { + IuUP_PDU_Type pdu_type, /* 0 */ + IuUP_FrameNr frame_nr, + IuUP_FQC fqc, + IuUP_RFCI rfci, + uint6_t header_crc, + uint10_t payload_crc, + octetstring payload +}; + +/* See TS 25.415 6.6.2.2 */ +type record IuUP_PDU_Type_1 { + IuUP_PDU_Type pdu_type, /* 1 */ + IuUP_FrameNr frame_nr, + IuUP_FQC fqc, + IuUP_RFCI rfci, + uint6_t header_crc, + BIT2 spare, + octetstring payload +}; + +/* See TS 25.415 6.6.6.2.3 */ +type record IuUP_PDU_Type_14 { + IuUP_PDU_Type pdu_type, + IuUP_AckNack ack_nack, + uint2_t frame_nr, + uint4_t iuup_version, + IuUP_ProcedureIndicator procedure_ind, + uint6_t header_crc, + uint10_t payload_crc, + IuUP_PDU14_Union u +} with { variant (u) "CROSSTAG( proc_sending, ack_nack=IuUP_ACKNACK_CTRL; + ack, ack_nack=IuUP_ACKNACK_ACK; + nack, ack_nack=IuUP_ACKNACK_NACK)" +}; + +/* 6.6.2.3.1 Figure 21 */ +type record IuUP_PDU14_ProcSending { + octetstring payload +}; + +/* 6.6.2.3.2 Figure 22 */ +type record IuUP_PDU14_ACK { + octetstring spare_ext optional +}; + +/* 6.6.2.3.3 Figure 23 */ +type record IuUP_PDU14_NACK { + IuUP_ErrorCause err_cause, + BIT2 spare, + octetstring spare_ext optional +}; + +type union IuUP_PDU14_Union { + IuUP_PDU14_ProcSending proc_sending, + IuUP_PDU14_ACK ack, + IuUP_PDU14_NACK nack +}; + +type union IuUP_PDU14_ProcSendingUnion { + IuUP_PDU14_ProcSending_INIT init, + IuUP_PDU14_ProcSending_RATE_CTRL rate_ctrl, + IuUP_PDU14_ProcSending_RATE_CTRL rate_ctrl_ack, + IuUP_PDU14_ProcSending_TIME_ALIGNMENT time_alignment, + IuUP_PDU14_ProcSending_ERROR_EVENT error_event +}; + +/* 6.6.2.3.4.1 Initialisation */ +type record IuUP_PDU14_ProcSending_INIT { + BIT3 spare, + boolean ti, + uint3_t subflows_per_rfci, + boolean chain_ind, + + /* FIXME: Further decode */ + octetstring payload +}; +type record IuUP_InitRfci { + boolean lri, + boolean li, + IuUP_RFCI rfci, + RecOfU8 len8 optional, + RecOfU16 len16 optional +} with { variant (len8) "PRESENCE(li=false)"; + variant (len16) "PRESENCE(li=true)" +}; +type record of uint8_t RecOfU8; +type record of uint16_t RecOfU16; + +/* 6.6.2.3.4.2.1 Rate Control procedure */ +type record IuUP_PDU14_ProcSending_RATE_CTRL { + BIT2 spare, + uint6_t nr_of_rfci_ind, + bitstring rfci_ind +} with { variant (nr_of_rfci_ind) "LENGTHTO(rfci_ind)" + variant (nr_of_rfci_ind) "UNIT(bits)" +}; + +/* 6.6.2.3.4.3 Time Alignment */ +type record IuUP_PDU14_ProcSending_TIME_ALIGNMENT { + uint8_t time_alignment, + octetstring spare optional +}; + +/* 6.6.2.3.4.4 Error Event */ +type record IuUP_PDU14_ProcSending_ERROR_EVENT { + IuUP_ErrorDistance distance, + IuUP_ErrorCause cause +}; + + +type union IuUP_PDU { + IuUP_PDU_Type_0 type_0, + IuUP_PDU_Type_1 type_1, + IuUP_PDU_Type_14 type_14 +} with { variant "TAG( type_0, pdu_type = 0; + type_1, pdu_type = 1; + type_14, pdu_type = 14;)" }; + +/* hand-written C++ functions */ +external function f_enc_IuUP_PDU(in IuUP_PDU msg) return octetstring; +external function f_IuUP_compute_crc_header(in octetstring inp) return uint6_t; +external function f_IuUP_compute_crc_payload(in octetstring inp) return uint10_t; + +/* auto-generated */ +external function dec_IuUP_PDU(in octetstring stream) return IuUP_PDU + with { extension "prototype(convert) decode(RAW)" }; + +template IuUP_PDU ts_IuUP_INIT_ACK(uint2_t frame_nr, uint4_t version) := { + type_14 := { + pdu_type := 14, + ack_nack := IuUP_ACKNACK_ACK, + frame_nr := frame_nr, + iuup_version := version, + procedure_ind := IuUP_PRI_INITIALIZATION, + header_crc := 0, + payload_crc := 0, + u := { + ack := { + spare_ext := omit + } + } + } +}; + +template IuUP_PDU tr_IuUP_INIT_ACK(template uint2_t frame_nr := ?, template uint4_t version := ?) := { + type_14 := { + pdu_type := 14, + ack_nack := IuUP_ACKNACK_ACK, + frame_nr := frame_nr, + iuup_version := version, + procedure_ind := IuUP_PRI_INITIALIZATION, + header_crc := ?, + payload_crc := ?, + u := { + ack := { + spare_ext := omit + } + } + } +}; + +template IuUP_PDU ts_IuUP_INIT(octetstring payload, uint2_t frame_nr := 0, uint4_t version := 0) := { + type_14 := { + pdu_type := 14, + ack_nack := IuUP_ACKNACK_CTRL, + frame_nr := frame_nr, + iuup_version := version, + procedure_ind := IuUP_PRI_INITIALIZATION, + header_crc := 0, + payload_crc := 0, + u := { + proc_sending := { + payload := payload + } + } + } +}; + +template IuUP_PDU tr_IuUP_INIT(template octetstring payload := ?, template uint2_t frame_nr := ?, + template uint4_t version := ?) := { + type_14 := { + pdu_type := 14, + ack_nack := IuUP_ACKNACK_CTRL, + frame_nr := frame_nr, + iuup_version := version, + procedure_ind := IuUP_PRI_INITIALIZATION, + header_crc := ?, + payload_crc := ?, + u := { + proc_sending := { + payload := payload + } + } + } +}; + + +template IuUP_PDU ts_IuUP_Type0(IuUP_FrameNr frame_nr, IuUP_RFCI rfci, octetstring payload, + IuUP_FQC fqc := IuUP_FQC_GOOD) := { + type_0 := { + pdu_type := 0, + frame_nr := frame_nr, + fqc := fqc, + rfci := rfci, + header_crc := 0, + payload_crc := 0, + payload := payload + } +}; + +template IuUP_PDU tr_IuUP_Type0(template IuUP_FrameNr frame_nr := ?, template IuUP_RFCI rfci := ?, + template IuUP_FQC fqc := ?) := { + type_0 := { + pdu_type := 0, + frame_nr := frame_nr, + fqc := fqc, + rfci := rfci, + header_crc := ?, + payload_crc := ?, + payload := ? + } +}; + +template IuUP_PDU ts_IuUP_Type1(IuUP_FrameNr frame_nr, IuUP_RFCI rfci, octetstring payload, + IuUP_FQC fqc := IuUP_FQC_GOOD) := { + type_1 := { + pdu_type := 1, + frame_nr := frame_nr, + fqc := fqc, + rfci := rfci, + header_crc := 0, + spare := '00'B, + payload := payload + } +}; + + +template IuUP_PDU tr_IuUP_Type1(template IuUP_FrameNr frame_nr := ?, template IuUP_RFCI rfci := ?, + template IuUP_FQC fqc := ?) := { + type_1 := { + pdu_type := 1, + frame_nr := frame_nr, + fqc := fqc, + rfci := rfci, + header_crc := ?, + spare := ?, + payload := ? + } +}; + + + +} with { encode "RAW" ; variant "FIELDORDER(msb)" } |