Add 3GPP TS 25.415 IuUP encoder/decoder
Change-Id: Ie04438d8ec2b796e9e56b1937fa024a5299457dd
This commit is contained in:
parent
38b2a10e0b
commit
c676c68de6
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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)" }
|
Loading…
Reference in New Issue