/* Data Types / Encoding / Decoding for OsmocomBB L1CTL interface */ /* (C) 2017 by Harald Welte , derived from l1ctl_proto.h * which is (C) 2010 by Harald Welte + Holger Hans Peter Freyther * All rights reserved. * * Released under the terms of GNU General Public License, Version 2 or * (at your option) any later version. * * SPDX-License-Identifier: GPL-2.0-or-later */ module L1CTL_Types { import from General_Types all; import from GSM_Types all; import from GSM_RR_Types all; import from Osmocom_Types all; type enumerated L1ctlMsgType { L1CTL_NONE, L1CTL_FBSB_REQ, L1CTL_FBSB_CONF, L1CTL_DATA_IND, L1CTL_RACH_REQ, L1CTL_DM_EST_REQ, L1CTL_DATA_REQ, L1CTL_RESET_IND, L1CTL_PM_REQ, /* power measurement */ L1CTL_PM_CONF, /* power measurement */ L1CTL_ECHO_REQ, L1CTL_ECHO_CONF, L1CTL_RACH_CONF, L1CTL_RESET_REQ, L1CTL_RESET_CONF, L1CTL_DATA_CONF, L1CTL_CCCH_MODE_REQ, L1CTL_CCCH_MODE_CONF, L1CTL_DM_REL_REQ, L1CTL_PARAM_REQ, L1CTL_DM_FREQ_REQ, L1CTL_CRYPTO_REQ, L1CTL_SIM_REQ, L1CTL_SIM_CONF, L1CTL_TCH_MODE_REQ, L1CTL_TCH_MODE_CONF, L1CTL_NEIGH_PM_REQ, L1CTL_NEIGH_PM_IND, L1CTL_TRAFFIC_REQ, L1CTL_TRAFFIC_CONF, L1CTL_TRAFFIC_IND, L1CTL_BURST_IND, L1CTL_GPRS_UL_TBF_CFG_REQ, L1CTL_GPRS_DL_TBF_CFG_REQ, L1CTL_GPRS_UL_BLOCK_REQ, L1CTL_GPRS_DL_BLOCK_IND, L1CTL_EXT_RACH_REQ, L1CTL_GPRS_RTS_IND, L1CTL_GPRS_UL_BLOCK_CNF } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlCcchMode { CCCH_MODE_NONE (0), CCCH_MODE_NON_COMBINED, CCCH_MODE_COMBINED, CCCH_MODE_COMBINED_CBCH } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlNeighMode { NEIGH_MODE_NONE (0), NEIGH_MODE_PM, NEIGH_MODE_SB } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlResetType { L1CTL_RES_T_BOOT (0), L1CTL_RES_T_FULL, L1CTL_RES_T_SCHED } with { variant "FIELDLENGTH(8)" }; type record L1ctlHdrFlags { BIT7 padding, boolean f_done } with { variant "" }; type record L1ctlHeader { L1ctlMsgType msg_type, L1ctlHdrFlags flags, OCT2 padding } with { variant "" }; template L1ctlHeader tr_L1ctlHeader(template (present) L1ctlMsgType msg_type) := { msg_type := msg_type, flags := ?, padding := ? }; template (value) L1ctlHeader ts_L1ctlHeader(template (value) L1ctlMsgType msg_type) := { msg_type := msg_type, flags := { padding := '0000000'B, f_done := false }, padding := '0000'O }; type record L1ctlDlInfo { RslChannelNr chan_nr, RslLinkId link_id, GsmBandArfcn arfcn, uint32_t frame_nr, GsmRxLev rx_level, uint8_t snr, uint8_t num_biterr, uint8_t fire_crc } with { variant "" }; type record L1ctlFbsbConf { int16_t initial_freq_err, uint8_t result, uint8_t bsic } with { variant "" }; type record L1ctlCcchModeConf { L1ctlCcchMode ccch_mode, OCT3 padding } with { variant "" }; /* gsm48_chan_mode */ type enumerated L1ctlTchMode { L1CTL_CHAN_MODE_SIGN ('00000000'B), /* Signalling */ L1CTL_CHAN_MODE_SPEECH_V1 ('00000001'B), /* FR or HR codec */ L1CTL_CHAN_MODE_SPEECH_V2 ('00100001'B), /* EFR codec */ L1CTL_CHAN_MODE_SPEECH_V3 ('01000001'B), /* AMR codec */ L1CTL_CHAN_MODE_DATA_14k5 ('00001111'B), /* CSD: TCH/F14.4 */ L1CTL_CHAN_MODE_DATA_12k0 ('00000011'B), /* CSD: TCH/F9.6 */ L1CTL_CHAN_MODE_DATA_6k0 ('00001011'B), /* CSD: TCH/{FH}4.8 */ L1CTL_CHAN_MODE_DATA_3k6 ('00010011'B) /* CSD: TCH/{FH}2.4 */ } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlLoopMode { L1CTL_LOOP_MODE_OPEN ('00000000'B), L1CTL_LOOP_MODE_A ('00000001'B), L1CTL_LOOP_MODE_B ('00000010'B), L1CTL_LOOP_MODE_C ('00000011'B), L1CTL_LOOP_MODE_D ('00000100'B), L1CTL_LOOP_MODE_E ('00000101'B), L1CTL_LOOP_MODE_F ('00000110'B), L1CTL_LOOP_MODE_I ('00000111'B) } with { variant "FIELDLENGTH(8)" }; type record L1ctlAudioMode { BIT4 padding, boolean tx_microphone, boolean tx_traffic_req, boolean rx_speaker, boolean rx_traffic_ind } with { variant "" }; template (value) L1ctlAudioMode t_L1CTL_AudioModeNone := { '0000'B, false, false, false, false }; /* Traffic forwarding mode (see TRAFFIC.{req,cnf,ind} messages) */ template (value) L1ctlAudioMode t_L1CTL_AudioModeFwd modifies t_L1CTL_AudioModeNone := { tx_traffic_req := true, rx_traffic_ind := true }; type record L1ctlTchModeConf { L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode, record { uint8_t start_codec, BIT8 codecs_bitmask } amr } with { variant "" }; type record L1ctlDataInd { octetstring payload } with { variant (payload) "BYTEORDER(first)" }; type record L1ctlUlInfo { RslChannelNr chan_nr, RslLinkId link_id, OCT2 padding } with { variant "" }; type record L1ctlFbsbFlags { BIT5 padding, boolean sb, boolean fb1, boolean fb0 } with { variant "FIELDORDER(msb)" }; template (value) L1ctlFbsbFlags t_L1CTL_FBSB_F_ALL := { padding := '00000'B, sb := true, fb1 := true, fb0 := true }; type record L1ctlFbsbReq { GsmBandArfcn arfcn, uint16_t timeout_tdma_frames, uint16_t freq_err_thresh1, uint16_t freq_err_thresh2, uint8_t num_freqerr_avg, L1ctlFbsbFlags flags, uint8_t sync_info_idx, L1ctlCcchMode ccch_mode, GsmRxLev rxlev_exp } with { variant "" }; type record L1ctlCcchModeReq { L1ctlCcchMode ccch_mode, OCT3 padding } with { variant "" }; type record L1ctlTchModeReq { L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode, L1ctlLoopMode loop_mode, record { uint8_t start_codec, BIT8 codecs_bitmask } amr } with { variant "" }; type record L1ctlRachReq { uint8_t ra, uint8_t combined, uint16_t offset } with { variant "" }; type enumerated L1ctlRachSynchSeq { RACH_SYNCH_SEQ_TS0 (0), RACH_SYNCH_SEQ_TS1, RACH_SYNCH_SEQ_TS2 } with { variant "FIELDLENGTH(8)" }; type record L1ctlExtRachReq { uint16_t ra11, L1ctlRachSynchSeq synch_seq, uint8_t combined, uint16_t offset } with { variant "" }; type record L1ctlParReq { int8_t ta, uint8_t tx_power, OCT2 padding } with { variant "" }; type record L1ctlDataReq { SacchL1Header l1header optional, octetstring l2_payload } with { variant "" }; type record L1ctlH0 { uint8_t h, GsmBandArfcn arfcn, octetstring padding length(130) } with { variant "" }; type record length(0..64) of GsmBandArfcn L1ctlMA; type record L1ctlH1 { uint8_t h, uint8_t hsn, uint8_t maio, uint8_t n, OCT1 spare, L1ctlMA ma, octetstring padding } with { variant (n) "LENGTHTO(ma)" variant (n) "UNIT(elements)" /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=562849. * TL;DR The reference point of the PADDING attribute is the beginning * of the message, not the beginning of the type/field it's applied on. * Therefore we cannot use it here, and have to add padding manually. * variant (ma) "PADDING(128)" */ }; type union L1ctlH0H1 { L1ctlH0 h0, L1ctlH1 h1 } with { variant "TAG(h0, h = 0; h1, h = 1)" }; type record L1ctlDmEstReq { GsmTsc tsc, L1ctlH0H1 h0h1, L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode } with { variant "" }; type record L1ctlReset { L1ctlResetType reset_type, OCT3 padding } with { variant "" }; type record L1CtlCryptoReq { uint8_t algo, uint8_t key_len, octetstring key } with { variant (key_len) "LENGTHTO(key)" }; type record L1ctlTrafficReq { octetstring data } with { variant (data) "BYTEORDER(first)" } /* payload of L1CTL_GPRS_UL_TBF_CFG_REQ */ type record L1ctlGprsUlTbfCfgReq { uint8_t tbf_ref, BIT8 slotmask, OCT2 pad ('0000'O), uint32_t start_fn /* TBF Starting Time (absolute Fn) */ } with { variant (slotmask) "BITORDER(msb)" }; /* payload of L1CTL_GPRS_DL_TBF_CFG_REQ */ type record L1ctlGprsDlTbfCfgReq { uint8_t tbf_ref, BIT8 slotmask, uint8_t dl_tfi, OCT1 pad ('00'O), uint32_t start_fn /* TBF Starting Time (absolute Fn) */ } with { variant (slotmask) "BITORDER(msb)" }; /* part of L1CTL_GPRS_{UL,DL}_BLOCK_{REQ,IND} */ type record L1ctlGprsBlockHdr { uint32_t fn, uint8_t tn, OCT3 pad ('000000'O) } with { variant "" }; /* payload of L1CTL_GPRS_UL_BLOCK_REQ */ type record L1ctlGprsUlBlockReq { L1ctlGprsBlockHdr hdr, octetstring data } with { variant (data) "BYTEORDER(first)" }; /* payload of L1CTL_GPRS_UL_BLOCK_CNF */ type record L1ctlGprsUlBlockCnf { uint32_t fn, uint8_t tn, octetstring data } with { variant "" }; /* payload of L1CTL_GPRS_DL_BLOCK_IND */ type record L1ctlGprsDlBlockInd { L1ctlGprsBlockHdr hdr, record { uint16_t ber10k, /* Bit Error Rate */ int16_t ci_cb, /* C/I in centiBels */ uint8_t rx_level /* RxLev 0..63 */ } meas, uint8_t usf, octetstring data } with { variant (data) "BYTEORDER(first)" }; /* payload of L1CTL_GPRS_RTS_IND */ type record L1ctlGprsRtsInd { uint32_t fn, uint8_t tn, uint8_t usf } with { variant "" }; type union L1ctlMsgPayload { L1ctlFbsbReq fbsb_req, L1ctlFbsbConf fbsb_conf, L1ctlDataInd data_ind, L1ctlRachReq rach_req, L1ctlDmEstReq dm_est_req, L1ctlDataReq data_req, /* TODO: L1CTL_RESET_IND */ /* TODO: L1CTL_PM_REQ */ /* TODO: L1CTL_PM_CONF */ L1ctlReset reset_req, L1ctlCcchModeReq ccch_mode_req, L1ctlCcchModeConf ccch_mode_conf, L1ctlParReq par_req, /* TODO: L1CTL_DM_FREQ_REQ */ L1CtlCryptoReq crypto_req, /* TODO: L1CTL_SIM_REQ */ /* TODO: L1CTL_SIM_CONF */ L1ctlTchModeReq tch_mode_req, L1ctlTchModeConf tch_mode_conf, /* TODO: L1CTL_NEIGH_PM_REQ */ /* TODO: L1CTL_NEIGH_PM_IND */ L1ctlTrafficReq traffic_req, L1ctlTrafficReq traffic_ind, /* TODO: L1CTL_BURST_IND */ L1ctlGprsUlTbfCfgReq ul_tbf_cfg_req, L1ctlGprsDlTbfCfgReq dl_tbf_cfg_req, L1ctlGprsUlBlockReq ul_block_req, L1ctlGprsUlBlockCnf ul_block_cnf, L1ctlGprsDlBlockInd dl_block_ind, L1ctlExtRachReq ext_rach_req, L1ctlGprsRtsInd rts_ind, octetstring other } with { variant (other) "BYTEORDER(first)" }; type record L1ctlMessage { L1ctlHeader header, L1ctlUlInfo ul_info optional, L1ctlDlInfo dl_info optional, L1ctlMsgPayload payload optional } with { variant (ul_info) "PRESENCE(header.msg_type = L1CTL_RACH_REQ, header.msg_type = L1CTL_EXT_RACH_REQ, header.msg_type = L1CTL_PARAM_REQ, header.msg_type = L1CTL_CRYPTO_REQ, header.msg_type = L1CTL_DATA_REQ, header.msg_type = L1CTL_DM_EST_REQ, header.msg_type = L1CTL_DM_FREQ_REQ, header.msg_type = L1CTL_DM_REL_REQ, header.msg_type = L1CTL_TRAFFIC_REQ)" variant (dl_info) "PRESENCE(header.msg_type = L1CTL_FBSB_CONF, header.msg_type = L1CTL_RACH_CONF, header.msg_type = L1CTL_DATA_IND, header.msg_type = L1CTL_DATA_CONF, header.msg_type = L1CTL_TRAFFIC_IND, header.msg_type = L1CTL_TRAFFIC_CONF)" variant (payload) "CROSSTAG(fbsb_req, header.msg_type = L1CTL_FBSB_REQ; fbsb_conf, header.msg_type = L1CTL_FBSB_CONF; data_ind, header.msg_type = L1CTL_DATA_IND; rach_req, header.msg_type = L1CTL_RACH_REQ; dm_est_req, header.msg_type = L1CTL_DM_EST_REQ; data_req, header.msg_type = L1CTL_DATA_REQ; /* TODO: reset_ind, header.msg_type = L1CTL_RESET_IND */ /* TODO: pm_req, header.msg_type = L1CTL_PM_REQ */ /* TODO: pm_conf, header.msg_type = L1CTL_PM_CONF */ reset_req, header.msg_type = L1CTL_RESET_REQ; ccch_mode_req, header.msg_type = L1CTL_CCCH_MODE_REQ; ccch_mode_conf, header.msg_type = L1CTL_CCCH_MODE_CONF; par_req, header.msg_type = L1CTL_PARAM_REQ; /* TODO: freq_req, header.msg_type = L1CTL_DM_FREQ_REQ */ crypto_req, header.msg_type = L1CTL_CRYPTO_REQ; /* TODO: sim_req, header.msg_type = L1CTL_SIM_REQ */ /* TODO: sim_conf, header.msg_type = L1CTL_SIM_CONF */ tch_mode_req, header.msg_type = L1CTL_TCH_MODE_REQ; tch_mode_conf, header.msg_type = L1CTL_TCH_MODE_CONF; /* TODO: neigh_pm_req, header.msg_type = L1CTL_NEIGH_PM_REQ */ /* TODO: neigh_pm_ind, header.msg_type = L1CTL_NEIGH_PM_IND */ traffic_req, header.msg_type = L1CTL_TRAFFIC_REQ; traffic_ind, header.msg_type = L1CTL_TRAFFIC_IND; /* TODO: burst_ind, header.msg_type = L1CTL_BURST_IND */ ul_tbf_cfg_req, header.msg_type = L1CTL_GPRS_UL_TBF_CFG_REQ; dl_tbf_cfg_req, header.msg_type = L1CTL_GPRS_DL_TBF_CFG_REQ; ul_block_req, header.msg_type = L1CTL_GPRS_UL_BLOCK_REQ; ul_block_cnf, header.msg_type = L1CTL_GPRS_UL_BLOCK_CNF; dl_block_ind, header.msg_type = L1CTL_GPRS_DL_BLOCK_IND; ext_rach_req, header.msg_type = L1CTL_EXT_RACH_REQ; rts_ind, header.msg_type = L1CTL_GPRS_RTS_IND; other, OTHERWISE; )" }; external function enc_L1ctlMessage(in L1ctlMessage msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlMessage(in octetstring stream) return L1ctlMessage with { extension "prototype(convert) decode(RAW)" }; type record L1ctlMessageLV { uint16_t len, L1ctlMessage msg } with { variant (len) "LENGTHTO(msg)" }; external function enc_L1ctlMessageLV(in L1ctlMessageLV msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlMessageLV(in octetstring stream) return L1ctlMessageLV with { extension "prototype(convert) decode(RAW)" }; /* for generating RESET_REQ */ template (value) L1ctlMessage t_L1ctlResetReq(template (value) L1ctlResetType rst_type) := { header := ts_L1ctlHeader(L1CTL_RESET_REQ), ul_info := omit, dl_info := omit, payload := { reset_req := { reset_type := rst_type, padding := '000000'O } } }; /* for generating FBSB_REQ */ template (value) L1ctlMessage ts_L1CTL_FBSB_REQ(template (value) GsmBandArfcn arfcn, template (value) L1ctlFbsbFlags flags, template (value) uint8_t sync_info_idx, template (value) L1ctlCcchMode ccch_mode, template (value) GsmRxLev rxlev_exp) := { header := ts_L1ctlHeader(L1CTL_FBSB_REQ), ul_info := omit, dl_info := omit, payload := { fbsb_req := { arfcn := arfcn, timeout_tdma_frames := 250, /* about 1s */ freq_err_thresh1 := 10000, freq_err_thresh2 := 800, num_freqerr_avg := 3, flags := flags, sync_info_idx := sync_info_idx, ccch_mode := ccch_mode, rxlev_exp := rxlev_exp } } }; /* for matching against incoming FBSB_CONF */ template L1ctlMessage tr_L1CTL_FBSB_CONF(template (present) uint8_t result) := { header := tr_L1ctlHeader(L1CTL_FBSB_CONF), ul_info := omit, dl_info := ?, payload := { fbsb_conf := { initial_freq_err := ?, result := result, bsic := ? } } }; template (value) L1ctlMessage ts_L1CTL_CCCH_MODE_REQ(template (value) L1ctlCcchMode ccch_mode) := { header := ts_L1ctlHeader(L1CTL_CCCH_MODE_REQ), ul_info := omit, dl_info := omit, payload := { ccch_mode_req := { ccch_mode := ccch_mode, padding := '000000'O } } }; template (value) L1ctlMessage ts_L1CTL_TCH_MODE_REQ(template (value) L1ctlTchMode tch_mode := L1CTL_CHAN_MODE_SIGN, template (value) L1ctlAudioMode audio_mode := t_L1CTL_AudioModeFwd, template (value) L1ctlLoopMode loop_mode := L1CTL_LOOP_MODE_OPEN, template (value) uint8_t amr_start_codec := 0, template (value) BIT8 amr_codecs_bitmask := '00000000'B) := { header := ts_L1ctlHeader(L1CTL_TCH_MODE_REQ), ul_info := omit, dl_info := omit, payload := { tch_mode_req := { tch_mode := tch_mode, audio_mode := audio_mode, loop_mode := loop_mode, amr := { start_codec := amr_start_codec, codecs_bitmask := amr_codecs_bitmask } } } }; template L1ctlMessage tr_L1CTL_MsgType(template (present) L1ctlMsgType msg_type) := { header := tr_L1ctlHeader(msg_type), ul_info := *, dl_info := *, payload := * } template L1ctlMessage tr_L1CTL_CCCH_MODE_CONF := tr_L1CTL_MsgType(L1CTL_CCCH_MODE_CONF); template (value) L1ctlMessage ts_L1CTL_RACH_REQ(template (value) uint8_t ra, template (value) uint8_t combined, template (value) uint16_t offset, template (value) RslChannelNr chan_nr := ts_RslChanNr_RACH(0), template (value) RslLinkId link_id := ts_RslLinkID_DCCH(0)) := { header := ts_L1ctlHeader(L1CTL_RACH_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, dl_info := omit, payload := { rach_req := { ra := ra, combined := combined, offset := offset } } } template (value) L1ctlMessage ts_L1CTL_EXT_RACH_REQ(template (value) uint16_t ra11, template (value) L1ctlRachSynchSeq seq, template (value) uint8_t combined, template (value) uint16_t offset) := { header := ts_L1ctlHeader(L1CTL_EXT_RACH_REQ), ul_info := { /* FIXME: both RSL chan_nr and link_id should be configurable */ chan_nr := ts_RslChanNr_RACH(0), link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, dl_info := omit, payload := { ext_rach_req := { ra11 := ra11, synch_seq := seq, combined := combined, offset := offset } } } template (value) L1ctlMessage ts_L1CTL_PAR_REQ(template (value) uint8_t ta, template (value) uint8_t tx_power) := { header := ts_L1ctlHeader(L1CTL_PARAM_REQ), ul_info := { chan_nr := ts_RslChanNr_RACH(0), link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, dl_info := omit, payload := { par_req := { ta := ta, tx_power := tx_power, padding := '0000'O } } } /* Base template to be inherited by ts_L1CTL_DM_EST_REQ_H0 and ts_L1CTL_DM_EST_REQ_H1 */ private template (value) L1ctlMessage ts_L1CTL_DM_EST_REQ(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc) := { header := ts_L1ctlHeader(L1CTL_DM_EST_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, dl_info := omit, payload := { dm_est_req := { tsc := tsc, h0h1 := -, tch_mode := L1CTL_CHAN_MODE_SIGN, audio_mode := t_L1CTL_AudioModeFwd } } } template (value) L1ctlMessage ts_L1CTL_DM_EST_REQ_H0(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc, template (value) GsmArfcn arfcn) modifies ts_L1CTL_DM_EST_REQ := { payload := { dm_est_req := { h0h1 := { h0 := { h := 0, arfcn := ts_GsmBandArfcn(arfcn), padding := f_pad_oct(''O, 130, '00'O) } } } } } template (value) L1ctlMessage ts_L1CTL_DM_EST_REQ_H1(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc, template (value) uint6_t hsn, template (value) uint6_t maio, template (value) L1ctlMA ma) modifies ts_L1CTL_DM_EST_REQ := { payload := { dm_est_req := { h0h1 := { h1 := { h := 1, hsn := hsn, maio := maio, n := sizeof(ma), spare := '00'O, ma := ma, /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=562849 */ padding := f_pad_oct(''O, (64 - sizeof(ma)) * 2, '00'O) } } } } } template (value) L1ctlMessage ts_L1CTL_DM_REL_REQ(template (value) RslChannelNr chan_nr) := { header := ts_L1ctlHeader(L1CTL_DM_REL_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, dl_info := omit, payload := omit } template (value) L1ctlMessage ts_L1CTL_DATA_REQ(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, octetstring l2_data) := { header := ts_L1ctlHeader(L1CTL_DATA_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, dl_info := omit, payload := { data_req := { l1header := omit, l2_payload := l2_data } } } template (value) L1ctlMessage ts_L1CTL_DATA_REQ_SACCH(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, template (value) SacchL1Header l1h, octetstring l2_data) := { header := ts_L1ctlHeader(L1CTL_DATA_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, dl_info := omit, payload := { data_req := { l1header := l1h, l2_payload := l2_data } } } template (value) L1ctlMessage ts_L1CTL_TRAFFIC_REQ(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, octetstring frame) := { header := ts_L1ctlHeader(L1CTL_TRAFFIC_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, dl_info := omit, payload := { traffic_req := { data := frame } } }; /* for matching against incoming RACH_CONF */ template L1ctlMessage tr_L1CTL_RACH_CONF := { header := tr_L1ctlHeader(L1CTL_RACH_CONF), ul_info := omit, dl_info := ?, payload := * }; /* for sending and matching L1CTL_DATA_IND */ template (value) L1ctlMessage ts_L1CTL_DATA_IND(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, template (value) octetstring l2_data, template (value) GsmBandArfcn arfcn, template (value) uint32_t fn := 1337, template (value) GsmRxLev rx_level := 63, template (value) uint8_t num_biterr := 0, template (value) uint8_t fire_crc := 0) := { header := ts_L1ctlHeader(L1CTL_DATA_IND), ul_info := omit, dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := arfcn, frame_nr := fn, rx_level := rx_level, snr := 0, num_biterr := num_biterr, fire_crc := fire_crc }, payload := { data_ind := { payload := l2_data } } }; template L1ctlMessage tr_L1CTL_DATA_IND(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) octetstring l2_data := ?, template (present) uint8_t num_biterr := 0, template (present) uint8_t fire_crc := 0) := { header := tr_L1ctlHeader(L1CTL_DATA_IND), ul_info := omit, dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := ?, frame_nr := ?, rx_level := ?, snr := ?, num_biterr := num_biterr, fire_crc := fire_crc }, payload := { data_ind := { payload := l2_data } } }; /* for sending and matching L1CTL_DATA_CONF */ template (value) L1ctlMessage ts_L1CTL_DATA_CONF(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, template (value) GsmBandArfcn arfcn, template (value) GsmFrameNumber fn) := { header := ts_L1ctlHeader(L1CTL_DATA_CONF), ul_info := omit, dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := arfcn, frame_nr := fn, rx_level := 0, snr := 0, num_biterr := 0, fire_crc := 0 }, payload := omit }; template L1ctlMessage tr_L1CTL_DATA_CONF(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) GsmBandArfcn arfcn := ?, template (present) GsmFrameNumber fn := ?) := { header := tr_L1ctlHeader(L1CTL_DATA_CONF), ul_info := omit, dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := arfcn, frame_nr := fn, rx_level := ?, snr := ?, num_biterr := ?, fire_crc := ? }, payload := omit }; /* for sending and matching L1CTL_TRAFFIC_CONF */ template (value) L1ctlMessage ts_L1CTL_TRAFFIC_CONF(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, template (value) GsmBandArfcn arfcn, template (value) GsmFrameNumber fn) modifies ts_L1CTL_DATA_CONF := { header := ts_L1ctlHeader(L1CTL_TRAFFIC_CONF) }; template L1ctlMessage tr_L1CTL_TRAFFIC_CONF(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) GsmBandArfcn arfcn := ?, template (present) GsmFrameNumber fn := ?) modifies tr_L1CTL_DATA_CONF := { header := tr_L1ctlHeader(L1CTL_TRAFFIC_CONF) }; /* for matching against incoming TRAFFIC_IND */ template L1ctlMessage tr_L1CTL_TRAFFIC_IND(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) octetstring frame := ?, template (present) uint8_t num_biterr := ?, template (present) uint8_t fire_crc := ?) := { header := tr_L1ctlHeader(L1CTL_TRAFFIC_IND), ul_info := omit, dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := ?, frame_nr := ?, rx_level := ?, snr := ?, num_biterr := num_biterr, fire_crc := fire_crc }, payload := { traffic_ind := { data := frame } } }; template (value) L1ctlMessage ts_L1CTL_CRYPTO_REQ(template (value) RslChannelNr chan_nr, template (value) uint8_t algo, template (value) octetstring key) := { header := ts_L1ctlHeader(L1CTL_CRYPTO_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, dl_info := omit, payload := { crypto_req := { algo := algo, key_len := 0, /* overwritten */ key := key } } }; template (value) L1ctlMessage ts_L1CTL_GPRS_UL_TBF_CFG_REQ(template (value) uint8_t tbf_ref, template (value) BIT8 slotmask := '00000000'B, template (value) uint32_t start_fn := c_UINT32_MAX) := { header := ts_L1ctlHeader(L1CTL_GPRS_UL_TBF_CFG_REQ), ul_info := omit, dl_info := omit, payload := { ul_tbf_cfg_req := { tbf_ref := tbf_ref, slotmask := slotmask, pad := '0000'O, start_fn := start_fn } } }; template L1ctlMessage tr_L1CTL_GPRS_UL_TBF_CFG_REQ(template (present) uint8_t tbf_ref := ?, template (present) BIT8 slotmask := ?, template (present) uint32_t start_fn := ?) := { header := tr_L1ctlHeader(L1CTL_GPRS_UL_TBF_CFG_REQ), ul_info := omit, dl_info := omit, payload := { ul_tbf_cfg_req := { tbf_ref := tbf_ref, slotmask := slotmask, pad := ?, start_fn := start_fn } } }; template (value) L1ctlMessage ts_L1CTL_GPRS_DL_TBF_CFG_REQ(template (value) uint8_t tbf_ref, template (value) BIT8 slotmask := '00000000'B, template (value) uint32_t start_fn := c_UINT32_MAX, template (value) uint5_t dl_tfi := 0) := { header := ts_L1ctlHeader(L1CTL_GPRS_DL_TBF_CFG_REQ), ul_info := omit, dl_info := omit, payload := { dl_tbf_cfg_req := { tbf_ref := tbf_ref, slotmask := slotmask, dl_tfi := dl_tfi, pad := '00'O, start_fn := start_fn } } }; template L1ctlMessage tr_L1CTL_GPRS_DL_TBF_CFG_REQ(template (present) uint8_t tbf_ref := ?, template (present) BIT8 slotmask := ?, template (present) uint32_t start_fn := ?, template (present) uint5_t dl_tfi := ?) := { header := tr_L1ctlHeader(L1CTL_GPRS_DL_TBF_CFG_REQ), ul_info := omit, dl_info := omit, payload := { dl_tbf_cfg_req := { tbf_ref := tbf_ref, slotmask := slotmask, dl_tfi := dl_tfi, pad := ?, start_fn := start_fn } } }; template (value) L1ctlMessage ts_L1CTL_GPRS_UL_BLOCK_REQ(template (value) GsmFrameNumber fn, template (value) uint3_t tn, template (value) octetstring data) := { header := ts_L1ctlHeader(L1CTL_GPRS_UL_BLOCK_REQ), ul_info := omit, dl_info := omit, payload := { ul_block_req := { hdr := { fn := fn, tn := tn, pad := '000000'O }, data := data } } }; template L1ctlMessage tr_L1CTL_GPRS_UL_BLOCK_REQ(template (present) GsmFrameNumber fn := ?, template (present) uint3_t tn := ?, template (present) octetstring data := ?) := { header := tr_L1ctlHeader(L1CTL_GPRS_UL_BLOCK_REQ), ul_info := omit, dl_info := omit, payload := { ul_block_req := { hdr := { fn := fn, tn := tn, pad := ? }, data := data } } }; template (value) L1ctlMessage ts_L1CTL_GPRS_DL_BLOCK_IND(template (value) GsmFrameNumber fn, template (value) uint3_t tn, template (value) uint3_t usf, template (value) octetstring data, template (value) uint16_t ber10k := 0, template (value) int16_t ci_cb := 180 /* 18 dB */, template (value) GsmRxLev rx_level := 63) := { header := ts_L1ctlHeader(L1CTL_GPRS_DL_BLOCK_IND), ul_info := omit, dl_info := omit, payload := { dl_block_ind := { hdr := { fn := fn, tn := tn, pad := '000000'O }, meas := { ber10k := ber10k, ci_cb := ci_cb, rx_level := rx_level }, usf := usf, data := data } } }; template L1ctlMessage tr_L1CTL_GPRS_DL_BLOCK_IND(template (present) GsmFrameNumber fn := ?, template (present) uint3_t tn := ?, template (present) uint3_t usf := ?, template (present) octetstring data := ?, template (present) uint16_t ber10k := ?, template (present) int16_t ci_cb := ?, template (present) GsmRxLev rx_level := ?) := { header := tr_L1ctlHeader(L1CTL_GPRS_DL_BLOCK_IND), ul_info := omit, dl_info := omit, payload := { dl_block_ind := { hdr := { fn := fn, tn := tn, pad := ? }, meas := { ber10k := ber10k, ci_cb := ci_cb, rx_level := rx_level }, usf := usf, data := data } } }; const octetstring c_DummyUI := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O; /* We use "BYTEORDER(last)" so we get little-endian integers. Unfortuantely, this also switches the byte ordering in octet strings, so we need to explicitly annotate them :/ */ } with { encode "RAW" };