module CBSP_Types {

/* CBSP_Types, defining abstract TTCN-3 data types for the CBSP protocol.
 *
 * CBSP is a ETSI/3GPP standard protocol used between CBC (Cell Broadcast Centre) 
 * and BSC (Base Station Controller) in 2G/GSM/GERAN networks. It is specified
 * in 3GPP TS 48.049.
 *
 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 */

import from General_Types all;
import from Osmocom_Types all;
import from BSSAP_Types all;


/* 8.2.2 Message Type */
type enumerated CBSP_MessageType {
	CBSP_MSGT_WRITE_REPLACE			('01'O),
	CBSP_MSGT_WRITE_REPLACE_COMPL		('02'O),
	CBSP_MSGT_WRITE_REPLACE_FAIL		('03'O),
	CBSP_MSGT_KILL				('04'O),
	CBSP_MSGT_KILL_COMPL			('05'O),
	CBSP_MSGT_KILL_FAIL			('06'O),
	CBSP_MSGT_LOAD_QUERY			('07'O),
	CBSP_MSGT_LOAD_QUERY_COMPL		('08'O),
	CBSP_MSGT_LOAD_QUERY_FAIL		('09'O),
	CBSP_MSGT_MSG_STATUS_QUERY		('0a'O),
	CBSP_MSGT_MSG_STATUS_QUERY_COMPL	('0b'O),
	CBSP_MSGT_MSG_STATUS_QUERY_FAIL		('0c'O),
	CBSP_MSGT_SET_DRX			('0d'O),
	CBSP_MSGT_SET_DRX_COMPL			('0e'O),
	CBSP_MSGT_SET_DRX_FAIL			('0f'O),
	CBSP_MSGT_RESET				('10'O),
	CBSP_MSGT_RESET_COMPL			('11'O),
	CBSP_MSGT_RESET_FAIL			('12'O),
	CBSP_MSGT_RESTART			('13'O),
	CBSP_MSGT_FAILURE			('14'O),
	CBSP_MSGT_ERROR_IND			('15'O),
	CBSP_MSGT_KEEP_ALIVE			('16'O),
	CBSP_MSGT_KEEP_ALIVE_COMPL		('17'O)
} with { variant "FIELDLENGTH(8)" };

/* 8.2.1 Information Element Identifier */
type enumerated CBSP_IEI {
	CBSP_IEI_MSG_CONTENT			('01'O),
	CBSP_IEI_OLD_SERIAL_NR			('02'O),
	CBSP_IEI_NEW_SERIAL_NR			('03'O),
	CBSP_IEI_CELL_LIST			('04'O),
	CBSP_IEI_CATEGORY			('05'O),
	CBSP_IEI_REP_PERIOD			('06'O),
	CBSP_IEI_NUM_BCAST_REQ			('07'O),
	CBSP_IEI_NUM_BCAST_COMPL_LIST		('08'O),
	CBSP_IEI_FAILURE_LIST			('09'O),
	CBSP_IEI_RR_LOADING_LIST		('0a'O),
	CBSP_IEI_CAUSE				('0b'O),
	CBSP_IEI_DCS				('0c'O),
	CBSP_IEI_RECOVERY_IND			('0d'O),
	CBSP_IEI_MSG_ID				('0e'O),
	CBSP_IEI_EMERG_IND			('0f'O),
	CBSP_IEI_WARN_TYPE			('10'O),
	CBSP_IEI_WARN_SEC_INFO			('11'O),
	CBSP_IEI_CHANNEL_IND			('12'O),
	CBSP_IEI_NUM_OF_PAGES			('13'O),
	CBSP_IEI_SCHEDULE_PERIOD		('14'O),
	CBSP_IEI_NUM_OF_RES_SLOTS		('15'O),
	CBSP_IEI_BCAST_MSG_TYPE			('16'O),
	CBSP_IEI_WARNING_PERIOD			('17'O),
	CBSP_IEI_KEEP_ALIVE_REP_PERIOD		('18'O)
} with { variant "FIELDLENGTH(8)" };

/* 8.2.7 Category */
type enumerated CBSP_Category {
	CBSP_CATEG_HIGH_PRIO			('00'O),
	CBSP_CATEG_BACKGROUND			('01'O),
	CBSP_CATEG_NORMAL			('02'O)
} with { variant "FIELDLENGTH(8)" };

/* Cell ID Discriminator (8.2.11, ...) */
type enumerated CBSP_CellIdDisc {
	CBSP_CIDD_WHOLE_CGI		(0),
	CBSP_CIDD_LAC_CI		(1),
	CBSP_CIDD_CI			(2),
	CBSP_CIDD_LAI			(4),
	CBSP_CIDD_LAC			(5),
	CBSP_CIDD_ALL_IN_BSC		(6)
} with { variant "FIELDLENGTH(4)" };

/* 8.2.13 Cause */
type enumerated CBSP_Cause {
	CBSP_CAUSE_PARAM_NOT_RECOGNISED		('00'O),
	CBSP_CAUSE_PARAM_VAL_INVALID		('01'O),
	CBSP_CAUSE_MSG_REF_NOT_IDENTIFIED	('02'O),
	CBSP_CAUSE_CELL_ID_NOT_VALID		('03'O),
	CBSP_CAUSE_UNRECOGNISED_MSG		('04'O),
	CBSP_CAUSE_MISSING_MAND_IE		('05'O),
	CBSP_CAUSE_BSC_CAPACITY_EXCEEDED	('06'O),
	CBSP_CAUSE_CELL_MEMORY_EXCEEDED		('07'O),
	CBSP_CAUSE_BSC_MEMORY_EXCEEDED		('08'O),
	CBSP_CAUSE_CB_NOT_SUPPORTED		('09'O),
	CBSP_CAUSE_CB_NOT_OPERATIONAL		('0a'O),
	CBSP_CAUSE_INCOMPATIBLE_DRX_PARAM	('0b'O),
	CBSP_CAUSE_EXT_CHAN_NOT_SUPPORTED	('0c'O),
	CBSP_CAUSE_MSG_REF_ALREADY_USED		('0d'O),
	CBSP_CAUSE_UNSPECIFIED_ERROR		('0e'O),
	CBSP_CAUSE_LAI_OR_LAC_NPT_VALID		('0f'O)
} with { variant "FIELDLENGTH(8)" };

type record CBSP_IE_MessageContent {
	uint8_t		user_len,
	octetstring	val
} with { variant (val) "FIELDLENGTH(82)"
         variant (val) "ALIGN(left)" };

/* 8.2.6 Cell List */
type record CBSP_IE_CellList {
	uint16_t	len,
	BIT4		spare1_4,
	BIT4		cell_id_discr,
	BSSMAP_FIELD_CellIdentificationList cell_id
} with {
	variant (len) "LENGTHTO(cell_id_discr,spare1_4,cell_id)"
	variant (cell_id) "CROSSTAG(
		cIl_CGI,		cell_id_discr = '0000'B;
		cIl_LAC_CI,		cell_id_discr = '0001'B;
		cIl_CI,			cell_id_discr = '0010'B;
		cIl_LAI,		cell_id_discr = '0100'B;
		cIl_LAC,		cell_id_discr = '0101'B;
		cIl_allInBSS,		cell_id_discr = '0110'B;
			)"
};

/* 8.2.10 Number of Broadcasts Completed List */
type record CBSP_IE_NumBcastComplList {
	uint16_t	len,
	BIT4		spare1_4,
	BIT4		cell_id_discr,
	CBSP_FIELD_NumBcastCompl list
} with {
	variant (len) "LENGTHTO(cell_id_discr,spare1_4,list)"
	variant (list) "CROSSTAG(
		cI_CGI,		cell_id_discr = '0000'B;
		cI_LAC_CI,	cell_id_discr = '0001'B;
		cI_CI,		cell_id_discr = '0010'B;
		cI_LAI,		cell_id_discr = '0100'B;
		cI_LAC,		cell_id_discr = '0101'B;
		cI_allInBSS,	cell_id_discr = '0110'B;
			)"
};
type union CBSP_FIELD_NumBcastCompl {
	CBSP_FIELD_NumBcastCompl_CGI		cI_CGI,
	CBSP_FIELD_NumBcastCompl_LAC_CI		cI_LAC_CI,
	OCT0					cI_allInBSS,
	CBSP_FIELD_NumBcastCompl_CI		cI_CI,
	CBSP_FIELD_NumBcastCompl_LAC		cI_LAC,
	CBSP_FIELD_NumBcastCompl_LAI		cI_LAI
};
type record CBSP_FIELD_NumBcastCompl_CGI {
	BSSMAP_FIELD_CellIdentification_CGI	ci,
	uint16_t				num_bcast_compl,
	CBSP_NumBcastInfo			num_bcast_info,
	BIT4					spare1_4
};
type record CBSP_FIELD_NumBcastCompl_LAC_CI {
	BSSMAP_FIELD_CellIdentification_LAC_CI	ci,
	uint16_t				num_bcast_compl,
	CBSP_NumBcastInfo			num_bcast_info,
	BIT4					spare1_4
};
type record CBSP_FIELD_NumBcastCompl_LAI {
	BSSMAP_FIELD_CellIdentification_LAI	ci,
	uint16_t				num_bcast_compl,
	CBSP_NumBcastInfo			num_bcast_info,
	BIT4					spare1_4
};
type record CBSP_FIELD_NumBcastCompl_CI {
	OCT2					ci,
	uint16_t				num_bcast_compl,
	CBSP_NumBcastInfo			num_bcast_info,
	BIT4					spare1_4
};
type record CBSP_FIELD_NumBcastCompl_LAC {
	OCT2					lac,
	uint16_t				num_bcast_compl,
	CBSP_NumBcastInfo			num_bcast_info,
	BIT4					spare1_4
};
type enumerated CBSP_NumBcastInfo {
	CBSP_NUM_BCAST_INFO_VALID	(0),
	CBSP_NUM_BCAST_INFO_OVERFLOW	(1),
	CBSP_NUM_BCAST_INFO_UNKNOWN	(2)
} with { variant "FIELDLENGTH(4)" };


/* 8.2.11 Failure List */
type record CBSP_FailureListItem {
	BIT4		spare1_4,
	BIT4		cell_id_discr,
	CBSP_FIELD_CellIdentification cell_id,
	CBSP_Cause	cause
} with {
	variant (cell_id) "CROSSTAG(
		cI_CGI,		cell_id_discr = '0000'B;
		cI_LAC_CI,	cell_id_discr = '0001'B;
		cI_CI,		cell_id_discr = '0010'B;
		cI_LAI,		cell_id_discr = '0100'B;
		cI_LAC,		cell_id_discr = '0101'B;
		cI_allInBSS,	cell_id_discr = '0110'B;
			)"
};
type union CBSP_FIELD_CellIdentification
{
	BSSMAP_FIELD_CellIdentification_CGI    cI_CGI,
	BSSMAP_FIELD_CellIdentification_LAC_CI cI_LAC_CI,
	OCT2                                   cI_CI,
	BSSMAP_FIELD_CellIdentification_LAI    cI_LAI,
	OCT2                                   cI_LAC,
	OCT2                                   cI_allInBSS
};

type record of CBSP_FailureListItem CBSP_FailureListItems;
type record CBSP_IE_FailureList {
	uint16_t	len,
	CBSP_FailureListItems list
} with {
	variant (len) "LENGTHTO(list)"
};

/* 8.2.12 RR Loading List */
type record CBSP_IE_RrLoadingList {
	uint16_t	len,
	BIT4		spare1_4,
	BIT4		cell_id_discr,
	CBSP_FIELD_RrLoadingList list
} with {
	variant (len) "LENGTHTO(cell_id_discr,spare1_4,list)"
	variant (list) "CROSSTAG(
		cI_CGI,		cell_id_discr = '0000'B;
		cI_LAC_CI,	cell_id_discr = '0001'B;
		cI_CI,		cell_id_discr = '0010'B;
		cI_LAI,		cell_id_discr = '0100'B;
		cI_LAC,		cell_id_discr = '0101'B;
		cI_allInBSS,	cell_id_discr = '0110'B;
			)"
};
type union CBSP_FIELD_RrLoadingList {
	CBSP_FIELD_RrLoadingList_CGI		cI_CGI,
	CBSP_FIELD_RrLoadingList_LAC_CI		cI_LAC_CI,
	OCT0					cI_allInBSS,
	CBSP_FIELD_RrLoadingList_CI		cI_CI,
	CBSP_FIELD_RrLoadingList_LAC		cI_LAC,
	CBSP_FIELD_RrLoadingList_LAI		cI_LAI
};
type record CBSP_FIELD_RrLoadingList_CGI {
	BSSMAP_FIELD_CellIdentification_CGI	ci,
	uint8_t					load1,
	uint8_t					load2
};
type record CBSP_FIELD_RrLoadingList_LAC_CI {
	BSSMAP_FIELD_CellIdentification_LAC_CI	ci,
	uint8_t					load1,
	uint8_t					load2
};
type record CBSP_FIELD_RrLoadingList_LAI {
	BSSMAP_FIELD_CellIdentification_LAI	ci,
	uint8_t					load1,
	uint8_t					load2
};
type record CBSP_FIELD_RrLoadingList_CI {
	OCT2					ci,
	uint8_t					load1,
	uint8_t					load2
};
type record CBSP_FIELD_RrLoadingList_LAC {
	OCT2					lac,
	uint8_t					load1,
	uint8_t					load2
};

/* 8.2.15 Recovery Indication */
type record CBSP_IE_RecoveryInd {
	BIT4			spare1_4,
	CBSP_RecoveryInd	recovery
};
type enumerated CBSP_RecoveryInd {
	CBSP_RI_DATA_AVAILABLE	(0),
	CBSP_RI_DATA_LOST	(1)
} with { variant "FIELDLENGTH(4)" };

/* 8.2.24 Broadcast Message Type */
type record CBSP_IE_BcastMsgType {
	BIT4			spare1_4,
	CBSP_BcastMsgType	msg_type
};
type enumerated CBSP_BcastMsgType {
	CBSP_BC_MSGT_CBS	(0),
	CBSP_BC_MSGT_EMERG	(1)
} with { variant "FIELDLENGTH(4)" };


type union CBSP_IE_Body {
	CBSP_IE_MessageContent	msg_content,
	uint16_t		old_ser_nr,
	uint16_t		new_ser_nr,
	CBSP_IE_CellList	cell_list,
	CBSP_Category		category,
	uint16_t		rep_period,
	uint16_t		num_bcast_req,
	CBSP_IE_NumBcastComplList num_bcast_compl_list,
	CBSP_IE_FailureList	failure_list,
	CBSP_IE_RrLoadingList	rr_loading_list,
	CBSP_Cause		cause,
	uint8_t 		dcs,
	CBSP_IE_RecoveryInd	recovery_ind,
	uint16_t		msg_id,
	uint8_t			emerg_ind,
	uint16_t		warn_type,
	octetstring		warn_sec_info,
	uint8_t			channel_ind,
	uint8_t			num_of_pages,
	uint8_t			schedule_period,
	uint8_t			num_of_res_slots,
	CBSP_IE_BcastMsgType	bcast_msg_type,
	uint8_t			warning_period,
	uint8_t			keep_alive_rep_period
} with {
	variant (warn_sec_info) "FIELDLENGTH(50)"
};

type record CBSP_IE {
	CBSP_IEI		iei,
	CBSP_IE_Body		body
} with {
	variant (body)	"CROSSTAG(	msg_content, iei = CBSP_IEI_MSG_CONTENT;
					old_ser_nr, iei = CBSP_IEI_OLD_SERIAL_NR;
					new_ser_nr, iei = CBSP_IEI_NEW_SERIAL_NR;
					cell_list, iei = CBSP_IEI_CELL_LIST;
					category, iei = CBSP_IEI_CATEGORY;
					rep_period, iei = CBSP_IEI_REP_PERIOD;
					num_bcast_req, iei = CBSP_IEI_NUM_BCAST_REQ;
					num_bcast_compl_list, iei = CBSP_IEI_NUM_BCAST_COMPL_LIST;
					failure_list, iei = CBSP_IEI_FAILURE_LIST;
					rr_loading_list, iei = CBSP_IEI_RR_LOADING_LIST;
					cause, iei = CBSP_IEI_CAUSE;
					dcs, iei = CBSP_IEI_DCS;
					recovery_ind, iei = CBSP_IEI_RECOVERY_IND;
					msg_id, iei = CBSP_IEI_MSG_ID;
					emerg_ind, iei = CBSP_IEI_EMERG_IND;
					warn_type, iei = CBSP_IEI_WARN_TYPE;
					warn_sec_info, iei = CBSP_IEI_WARN_SEC_INFO;
					channel_ind, iei = CBSP_IEI_CHANNEL_IND;
					num_of_pages, iei = CBSP_IEI_NUM_OF_PAGES;
					schedule_period, iei = CBSP_IEI_SCHEDULE_PERIOD;
					num_of_res_slots, iei = CBSP_IEI_NUM_OF_RES_SLOTS;
					bcast_msg_type, iei = CBSP_IEI_BCAST_MSG_TYPE;
					warning_period, iei = CBSP_IEI_WARNING_PERIOD;
					keep_alive_rep_period, iei = CBSP_IEI_KEEP_ALIVE_REP_PERIOD
		)"
};

type set of CBSP_IE CBSP_IEs;

type record CBSP_PDU {
	CBSP_MessageType	msg_type,
	uint24_t		len,
	CBSP_IEs		ies
} with {
	variant (len) "LENGTHTO(ies)"
};

external function enc_CBSP_PDU(in CBSP_PDU msg) return octetstring
	with { extension "prototype(convert) encode(RAW)" };

external function dec_CBSP_PDU(in octetstring msg) return CBSP_PDU
	with { extension "prototype(convert) decode(RAW)" };

/* convert from warning period encoding to seconds */
function f_cbsp_period2s(uint8_t period) return integer
{
	if (period == 0) {
		return -1; /* infinite */
	} else if (period <= 10) {
		return period;
	} else if (period <= 20) {
		return 10 + (period - 10)*2;
	} else if (period <= 38) {
		return 30 + (period - 20)*5;
	} else if (period <= 86) {
		return 120 + (period - 38)*10;
	} else if (period <= 186) {
		return 600 + (period - 86)*30;
	} else {
		return 0;
	}
}

} with { encode "RAW"; variant "FIELDORDER(msb)" }