module CBSP_Templates {

import from Osmocom_Types all;
import from BSSAP_Types all;
import from CBSP_Types all;

/* TODO: receive templates must match IEs in any arbitrary order */

/* For some reason the TTCN-3 RAW codec cannot automatically figure out the IEI
 * that it needs to set for a given union-choice (body).  So we have to explicitly
 * specify the IEI by the caller :( */
template (value) CBSP_IE ts_CBSP_IE(CBSP_IEI iei, template (value) CBSP_IE_Body body) := {
	iei := iei,
	body := body
}

template CBSP_IE tr_CBSP_IE(template CBSP_IE_Body body) := {
	iei := ?,
	body := body
}


template (value) CBSP_IE ts_CbspMsgId(template (value) uint16_t val) :=
	ts_CBSP_IE(CBSP_IEI_MSG_ID, {msg_id := val});
template CBSP_IE tr_CbspMsgId(template uint16_t val := ?) :=
	tr_CBSP_IE({msg_id := val});

template (value) CBSP_IE ts_NewSerNo(template (value) uint16_t val) :=
	ts_CBSP_IE(CBSP_IEI_NEW_SERIAL_NR, {new_ser_nr := val});
template CBSP_IE tr_NewSerNo(template uint16_t val := ?) :=
	tr_CBSP_IE({new_ser_nr := val});

template (value) CBSP_IE ts_OldSerNo(template (value) uint16_t val) :=
	ts_CBSP_IE(CBSP_IEI_OLD_SERIAL_NR, {old_ser_nr := val});
template CBSP_IE tr_OldSerNo(template uint16_t val := ?) :=
	tr_CBSP_IE({old_ser_nr := val});

template (value) CBSP_IE ts_CbspKARepPeriod(template (value) uint8_t rep_per) :=
	ts_CBSP_IE(CBSP_IEI_KEEP_ALIVE_REP_PERIOD, {keep_alive_rep_period := rep_per});
template CBSP_IE tr_CbspKARepPeriod(template uint8_t rep_per := ?) :=
	tr_CBSP_IE({keep_alive_rep_period := rep_per});

function ts_CbspChannelInd(template (omit) uint8_t val) return template (omit) CBSP_IE {
	var template (omit) CBSP_IE ie;
	if (istemplatekind(val, "omit")) {
		ie := omit;
	} else {
		ie := ts_CBSP_IE(CBSP_IEI_CHANNEL_IND, {channel_ind := val});
	}
	return ie;
}
function tr_CbspChannelInd(template uint8_t val := ?) return template CBSP_IE {
	var template CBSP_IE ie;
	if (istemplatekind(val, "omit")) {
		ie := omit;
	} else if (istemplatekind(val, "*")) {
		ie := tr_CBSP_IE({channel_ind := ?}); //ifpresent;
	} else {
		ie := tr_CBSP_IE({channel_ind := val});
	}
	return ie;
}

template (value) CBSP_IE ts_CbspCause(template (value) CBSP_Cause c) :=
	ts_CBSP_IE(CBSP_IEI_CAUSE, {cause := c});
template CBSP_IE tr_CbspCause(template CBSP_Cause c := ?) :=
	tr_CBSP_IE({cause := c});

template (value) CBSP_IE ts_CbspCellList(template (value) BSSMAP_FIELD_CellIdentificationList list) :=
	ts_CBSP_IE(CBSP_IEI_CELL_LIST, {
			cell_list := {
				len := 0,
				spare1_4 := '0000'B,
				cell_id_discr := '0000'B,
				cell_id := list
			}});
template CBSP_IE tr_CbspCellList(template BSSMAP_FIELD_CellIdentificationList list := ?) :=
	tr_CBSP_IE({
			cell_list := {
				len := ?,
				spare1_4 := ?,
				cell_id_discr := ?,
				cell_id := list
			}});

template (value) CBSP_IE ts_CbspCategory(template (value) CBSP_Category cat) :=
	ts_CBSP_IE(CBSP_IEI_CATEGORY, {category := cat});
template CBSP_IE tr_CbspCategory(template CBSP_Category cat := ?) :=
	tr_CBSP_IE({category := cat});

template (value) CBSP_IE ts_CbspRepetitionPeriod(template (value) uint16_t per) :=
	ts_CBSP_IE(CBSP_IEI_REP_PERIOD, {rep_period := per});
template CBSP_IE tr_CbspRepetitionPeriod(template uint16_t per := ?) :=
	tr_CBSP_IE({rep_period := per});

template (value) CBSP_IE ts_CbspNumBcastReq(template (value) uint16_t num) :=
	ts_CBSP_IE(CBSP_IEI_NUM_BCAST_REQ, {num_bcast_req := num});
template CBSP_IE tr_CbspNumBcastReq(template uint16_t num := ?) :=
	tr_CBSP_IE({num_bcast_req := num});

template (value) CBSP_IE ts_CbspNumPages(template (value) uint8_t num) :=
	ts_CBSP_IE(CBSP_IEI_NUM_OF_PAGES, {num_of_pages := num});
template CBSP_IE tr_CbspNumPages(template uint16_t num := ?) :=
	tr_CBSP_IE({num_of_pages := num});

template (value) CBSP_IE ts_EmergencyInd(template (value) uint8_t val) :=
	ts_CBSP_IE(CBSP_IEI_EMERG_IND, {emerg_ind := val});
template CBSP_IE tr_EmergencyInd(template uint8_t val := ?) :=
	tr_CBSP_IE({emerg_ind := val});

template (value) CBSP_IE ts_WarningType(template (value) uint16_t val) :=
	ts_CBSP_IE(CBSP_IEI_WARN_TYPE, {warn_type := val});
template CBSP_IE tr_WarningType(template uint16_t val) :=
	tr_CBSP_IE({warn_type := val});

template (value) CBSP_IE ts_WarnSecInfo(template (value) octetstring payl := ''O) :=
	ts_CBSP_IE(CBSP_IEI_WARN_SEC_INFO, {warn_sec_info := payl});
template CBSP_IE tr_WarnSecInfo(template octetstring payl := ?) :=
	tr_CBSP_IE({warn_sec_info := payl});

template (value) CBSP_IE ts_WarningPeriod(template (value) uint8_t val) :=
	ts_CBSP_IE(CBSP_IEI_WARNING_PERIOD, {warning_period := val});
template CBSP_IE tr_WarningPeriod(template uint8_t val := ?) :=
	tr_CBSP_IE({warning_period := val});

template (value) CBSP_IE ts_CbspFailList(template (value) CBSP_FailureListItems items) :=
	ts_CBSP_IE(CBSP_IEI_FAILURE_LIST, {failure_list := {
						len := 0,
						list := items
				}});
template CBSP_IE tr_CbspFailList(template CBSP_FailureListItems items := ?) :=
	tr_CBSP_IE({failure_list := {
						len := ?,
						list := items
				}});

template (value) CBSP_IE ts_CbspNumComplList(template (value) CBSP_IE_NumBcastComplList list) :=
	ts_CBSP_IE(CBSP_IEI_NUM_BCAST_COMPL_LIST, {num_bcast_compl_list := list});
template CBSP_IE tr_CbspNumComplList(template CBSP_IE_NumBcastComplList list := ?) :=
	tr_CBSP_IE({num_bcast_compl_list := list});

template (value) CBSP_IE ts_CbspBcastMsgType(template (value) CBSP_BcastMsgType bi) :=
	ts_CBSP_IE(CBSP_IEI_BCAST_MSG_TYPE, {bcast_msg_type := {
			spare1_4 := '0000'B,
			msg_type := bi
		}});
template CBSP_IE tr_CbspBcastMsgType(template CBSP_BcastMsgType bi := ?) :=
	tr_CBSP_IE({bcast_msg_type := {
			spare1_4 := ?,
			msg_type := bi
		}});

template (value) CBSP_IE ts_CbspRecoveryInd(template (value) CBSP_RecoveryInd ri) :=
	ts_CBSP_IE(CBSP_IEI_RECOVERY_IND, {recovery_ind := {
			spare1_4 := '0000'B,
			recovery := ri
		}});
template CBSP_IE tr_CbspRecoveryInd(template CBSP_RecoveryInd ri) :=
	tr_CBSP_IE({recovery_ind := {
			spare1_4 := ?,
			recovery := ri
		}});

template (value) CBSP_IE ts_CbspMsgContent(template (value) octetstring payload, uint8_t user_len) :=
	ts_CBSP_IE(CBSP_IEI_MSG_CONTENT, {msg_content := {
			user_len := user_len,
			val := payload
		}});
template CBSP_IE tr_CbspMsgContent(template octetstring payload := ?, template uint8_t user_len := ?) :=
	tr_CBSP_IE({msg_content := {
			user_len := user_len,
			val := payload
		}});

template (value) CBSP_IE ts_CbspDCS(template (value) uint8_t dcs) :=
	ts_CBSP_IE(CBSP_IEI_DCS, {dcs := dcs});
template CBSP_IE tr_CbspDCS(template uint8_t dcs := ?) :=
	tr_CBSP_IE({dcs := dcs});


template (value) CBSP_PDU ts_CBSP(CBSP_MessageType msg_type, template (value) CBSP_IEs ies) := {
	msg_type := msg_type,
	len := 0, /* overwritten */
	ies := ies
}
template CBSP_PDU tr_CBSP(template CBSP_MessageType msg_type := ?, template CBSP_IEs ies := *) := {
	msg_type := msg_type,
	len := ?,
	ies := ies
}



/* 8.1.3.1 WRITE REPLACE */
function ts_CBSP_WRITE_CBS(template (value) uint16_t msg_id,
			    template (value) uint16_t new_ser_nr,
			    template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
			    template (value) uint8_t channel_ind,
			    template (value) CBSP_Category category,
			    template (value) uint16_t rep_period,
			    template (value) uint16_t num_bcast_req,
			    template (value) uint8_t dcs,
			    template (value) CBSP_IEs content) return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr),
		ts_CbspCellList(cell_list),
		ts_CbspChannelInd(channel_ind),
		ts_CbspCategory(category),
		ts_CbspRepetitionPeriod(rep_period),
		ts_CbspNumBcastReq(num_bcast_req),
		ts_CbspDCS(dcs),
		ts_CbspNumPages(lengthof(content))
	};
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE, valueof(ies) & valueof(content));
}
template CBSP_PDU tr_CBSP_WRITE_CBS(template uint16_t msg_id := ?, template uint16_t new_ser_nr := ?,
				    template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
				    template uint8_t channel_ind := ?,
				    template CBSP_Category category := ?,
				    template uint16_t rep_period := ?,
				    template uint16_t num_bcast_req := ?,
				    template uint8_t dcs := ?,
				    template CBSP_IEs content := ?
				    ) :=
	tr_CBSP(CBSP_MSGT_WRITE_REPLACE, ({
			tr_CbspMsgId(msg_id),
			tr_NewSerNo(new_ser_nr),
			tr_CbspCellList(cell_list),
			tr_CbspChannelInd(channel_ind),
			tr_CbspCategory(category),
			tr_CbspRepetitionPeriod(rep_period),
			tr_CbspNumBcastReq(num_bcast_req),
			tr_CbspDCS(dcs),
			tr_CbspNumPages(lengthof(content)), all from content }));


function ts_CBSP_REPLACE_CBS(uint16_t msg_id, uint16_t new_ser_nr, uint16_t old_ser_nr,
			    template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
			    template (value) uint8_t channel_ind,
			    template (value) CBSP_Category category,
			    template (value) uint16_t rep_period,
			    template (value) uint16_t num_bcast_req,
			    template (value) uint8_t dcs,
			    template (value) CBSP_IEs content) return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr),
		ts_OldSerNo(old_ser_nr),
		ts_CbspCellList(cell_list),
		ts_CbspChannelInd(channel_ind),
		ts_CbspCategory(category),
		ts_CbspRepetitionPeriod(rep_period),
		ts_CbspNumBcastReq(num_bcast_req),
		ts_CbspDCS(dcs),
		ts_CbspNumPages(lengthof(content))
	};
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE, valueof(ies) & valueof(content));
}
template CBSP_PDU tr_CBSP_REPLACE_CBS(template uint16_t msg_id := ?, template uint16_t new_ser_nr := ?,
				      template uint16_t old_ser_nr := ?,
				      template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
				      template uint8_t channel_ind := ?,
				      template CBSP_Category category := ?,
				      template uint16_t rep_period := ?,
				      template uint16_t num_bcast_req := ?,
				      template uint8_t dcs := ?,
				      template CBSP_IEs content := ?
				    ) :=
	tr_CBSP(CBSP_MSGT_WRITE_REPLACE, ({
			tr_CbspMsgId(msg_id),
			tr_NewSerNo(new_ser_nr),
			tr_OldSerNo(old_ser_nr),
			tr_CbspCellList(cell_list),
			tr_CbspChannelInd(channel_ind),
			tr_CbspCategory(category),
			tr_CbspRepetitionPeriod(rep_period),
			tr_CbspNumBcastReq(num_bcast_req),
			tr_CbspDCS(dcs),
			tr_CbspNumPages(lengthof(content)), all from content }));

template (value) CBSP_PDU ts_CBSP_WRITE_EMERG(uint16_t msg_id, uint16_t new_ser_nr,
						template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
						template (value) uint8_t emerg_ind,
						template (value) uint16_t warn_type,
						template (value) uint8_t warn_per
					    ) :=
	ts_CBSP(CBSP_MSGT_WRITE_REPLACE, {
			ts_CbspMsgId(msg_id),
			ts_NewSerNo(new_ser_nr),
			ts_CbspCellList(cell_list),
			ts_EmergencyInd(emerg_ind),
			ts_WarningType(warn_type),
			ts_WarnSecInfo,
			ts_WarningPeriod(warn_per) });
template CBSP_PDU tr_CBSP_WRITE_EMERG(template uint16_t msg_id := ?, template uint16_t new_ser_nr := ?,
					template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
					template uint8_t emerg_ind := ?,
					template uint16_t warn_type := ?,
					template uint16_t num_bcast_req := ?,
					template uint8_t warn_per := ?
				    ) :=
	tr_CBSP(CBSP_MSGT_WRITE_REPLACE, {
			tr_CbspMsgId(msg_id),
			tr_NewSerNo(new_ser_nr),
			tr_CbspCellList(cell_list),
			tr_EmergencyInd(emerg_ind),
			tr_WarningType(warn_type),
			tr_WarnSecInfo,
			tr_WarningPeriod(warn_per) });


template (value) CBSP_PDU ts_CBSP_REPLACE_EMERG(uint16_t msg_id, uint16_t new_ser_nr, uint16_t old_ser_nr,
						template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
						template (value) uint8_t emerg_ind,
						template (value) uint16_t warn_type,
						template (value) uint16_t num_bcast_req,
						template (value) uint8_t warn_per
					    ) :=
	ts_CBSP(CBSP_MSGT_WRITE_REPLACE, {
			ts_CbspMsgId(msg_id),
			ts_NewSerNo(new_ser_nr),
			ts_OldSerNo(old_ser_nr),
			ts_CbspCellList(cell_list),
			ts_EmergencyInd(emerg_ind),
			ts_WarningType(warn_type),
			ts_WarnSecInfo,
			ts_WarningPeriod(warn_per) });
template CBSP_PDU tr_CBSP_REPLACE_EMERG(template uint16_t msg_id := ?, template uint16_t new_ser_nr := ?,
					template uint16_t old_ser_nr := ?,
					template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
					template uint8_t emerg_ind := ?,
					template uint16_t warn_type := ?,
					template uint16_t num_bcast_req := ?,
					template uint8_t warn_per := ?
				    ) :=
	tr_CBSP(CBSP_MSGT_WRITE_REPLACE, {
			tr_CbspMsgId(msg_id),
			tr_NewSerNo(new_ser_nr),
			tr_OldSerNo(old_ser_nr),
			tr_CbspCellList(cell_list),
			tr_EmergencyInd(emerg_ind),
			tr_WarningType(warn_type),
			tr_WarnSecInfo,
			tr_WarningPeriod(warn_per) });

/* 8.1.3.2 WRITE-REPLACE COMPLETE */
function ts_CBSP_WRITE_CBS_COMPL(uint16_t msg_id, uint16_t new_ser_nr,
				 template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
				 template (value) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr)
	};
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE_COMPL, ies);
}
function tr_CBSP_WRITE_CBS_COMPL(template uint16_t msg_id, template uint16_t new_ser_nr,
				 template BSSMAP_FIELD_CellIdentificationList cell_list,
				 template uint8_t channel_ind)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_NewSerNo(new_ser_nr)
	};
	if (istemplatekind(cell_list, "*")) {
		testcase.stop("TITAN > 6.5.0 doesn't support this");
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (istemplatekind(cell_list, "?")) {
		ies[lengthof(ies)] := tr_CbspCellList(?);
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspCellList(cell_list);
	}
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := tr_CbspChannelInd(channel_ind);
	}
	return tr_CBSP(CBSP_MSGT_WRITE_REPLACE_COMPL, ies);
}


function ts_CBSP_REPLACE_CBS_COMPL(uint16_t msg_id, uint16_t new_ser_nr, uint16_t old_ser_nr,
				   template (value) CBSP_IE_NumBcastComplList compl_list,
				   template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
				   template (value) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr),
		ts_OldSerNo(old_ser_nr),
		ts_CbspNumComplList(compl_list)
	};
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE_COMPL, ies);
}
function tr_CBSP_REPLACE_CBS_COMPL(template uint16_t msg_id, template uint16_t new_ser_nr,
				   template uint16_t old_ser_nr,
				   template CBSP_IE_NumBcastComplList compl_list,
				   template BSSMAP_FIELD_CellIdentificationList cell_list,
				   template uint8_t channel_ind)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_NewSerNo(new_ser_nr),
		tr_OldSerNo(old_ser_nr),
		tr_CbspNumComplList(compl_list)
	};
	if (istemplatekind(cell_list, "*")) {
		testcase.stop("TITAN > 6.5.0 doesn't support this");
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (istemplatekind(cell_list, "?")) {
		ies[lengthof(ies)] := tr_CbspCellList(?);
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspCellList(cell_list);
	}
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := tr_CbspChannelInd(channel_ind);
	}
	return tr_CBSP(CBSP_MSGT_WRITE_REPLACE_COMPL, ies);
}


/* 8.1.3.3 WRITE-REPLACE FAILURE */
function ts_CBSP_WRITE_CBS_FAIL(uint16_t msg_id, uint16_t new_ser_nr,
				template (value) CBSP_FailureListItems fail_list,
				template (omit) CBSP_IE_NumBcastComplList compl_list,
				template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
				template (value) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr),
		ts_CbspFailList(fail_list)
	};
	if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspNumComplList(valueof(compl_list));
	}
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE_FAIL, ies);
}
function tr_CBSP_WRITE_CBS_FAIL(template uint16_t msg_id, template uint16_t new_ser_nr,
				template CBSP_FailureListItems fail_list,
				template CBSP_IE_NumBcastComplList compl_list,
				template BSSMAP_FIELD_CellIdentificationList cell_list,
				template uint8_t channel_ind)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_NewSerNo(new_ser_nr),
		tr_CbspFailList(fail_list)
	};
	if (istemplatekind(compl_list, "*")) {
		//ies[lengthof(ies)] := tr_CbspNumComplList ifpresent;
	} else if (istemplatekind(compl_list, "?")) {
		ies[lengthof(ies)] := tr_CbspNumComplList(?);
	} else if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspNumComplList(compl_list);
	}
	if (istemplatekind(cell_list, "*")) {
		testcase.stop("TITAN > 6.5.0 doesn't support this");
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (istemplatekind(cell_list, "?")) {
		ies[lengthof(ies)] := tr_CbspCellList(?);
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspCellList(cell_list);
	}
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	}
	return tr_CBSP(CBSP_MSGT_WRITE_REPLACE_FAIL, ies);
}


function ts_CBSP_REPLACE_CBS_FAIL(uint16_t msg_id, uint16_t new_ser_nr, uint16_t old_ser_nr,
				   template (value) CBSP_FailureListItems fail_list,
				   template (omit) CBSP_IE_NumBcastComplList compl_list,
				   template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
				   template (value) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_NewSerNo(new_ser_nr),
		ts_OldSerNo(old_ser_nr),
		ts_CbspFailList(fail_list)
	};
	if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspNumComplList(valueof(compl_list));
	}
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	return ts_CBSP(CBSP_MSGT_WRITE_REPLACE_FAIL, ies);
}
function tr_CBSP_REPLACE_CBS_FAIL(template uint16_t msg_id, template uint16_t new_ser_nr,
				   template uint16_t old_ser_nr,
				   template CBSP_FailureListItems fail_list,
				   template CBSP_IE_NumBcastComplList compl_list,
				   template BSSMAP_FIELD_CellIdentificationList cell_list,
				   template uint8_t channel_ind)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_NewSerNo(new_ser_nr),
		tr_OldSerNo(old_ser_nr),
		tr_CbspFailList(fail_list)
	};
	if (istemplatekind(compl_list, "*")) {
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (istemplatekind(compl_list, "?")) {
		ies[lengthof(ies)] := tr_CbspNumComplList(?);
	} else if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspNumComplList(compl_list);
	}
	if (istemplatekind(cell_list, "*")) {
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (istemplatekind(cell_list, "?")) {
		ies[lengthof(ies)] := tr_CbspCellList(?);
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspCellList(cell_list);
	}
	ies[lengthof(ies)] := tr_CbspChannelInd(channel_ind);
	return tr_CBSP(CBSP_MSGT_WRITE_REPLACE_FAIL, ies);
}

/* 8.1.3.4 KILL */
template (value) CBSP_PDU ts_CBSP_KILL(template (value) uint16_t msg_id,
					template (value) uint16_t old_ser_nr,
					template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
					template (omit) uint8_t channel_ind) :=
	ts_CBSP(CBSP_MSGT_KILL, {
			ts_CbspMsgId(msg_id),
			ts_OldSerNo(old_ser_nr),
			ts_CbspCellList(cell_list),
			ts_CbspChannelInd(channel_ind)});
function tr_CBSP_KILL(template uint16_t msg_id := ?, template uint16_t old_ser_nr := ?,
			template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
			template uint8_t channel_ind := ?)
return template (present) CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_OldSerNo(old_ser_nr),
		tr_CbspCellList(cell_list)
	};
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := tr_CbspChannelInd(channel_ind);
	}
	return tr_CBSP(CBSP_MSGT_KILL, ies);
}

/* 8.1.3.5 KILL COMPLETE */
function ts_CBSP_KILL_COMPL(template (value) uint16_t msg_id, template (value) uint16_t old_ser_nr,
			    template (omit) CBSP_IE_NumBcastComplList compl_list,
			    template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
			    template (omit) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_OldSerNo(old_ser_nr)
	};
	if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspNumComplList(valueof(compl_list));
	}
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	}
	return ts_CBSP(CBSP_MSGT_KILL_COMPL, ies);
}
function tr_CBSP_KILL_COMPL(template uint16_t msg_id := ?, template uint16_t old_ser_nr := ?,
			    template CBSP_IE_NumBcastComplList compl_list := ?,
			    template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
			    template uint8_t channel_ind)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_OldSerNo(old_ser_nr)
	};
	/* As soon as adding a '*' IE item, lengthof() no longer works on the ies record. So keep track of the
	 * next index to use separately. */
	var integer next_idx := lengthof(ies);
	if (istemplatekind(compl_list, "*")) {
		ies[next_idx] := *;
		next_idx := next_idx + 1;
	} else if (not istemplatekind(compl_list, "omit")) {
		ies[next_idx] := tr_CbspNumComplList(compl_list);
		next_idx := next_idx + 1;
	}
	if (istemplatekind(cell_list, "*")) {
		ies[next_idx] := *;
		next_idx := next_idx + 1;
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[next_idx] := tr_CbspCellList(cell_list);
		next_idx := next_idx + 1;
	}
	if (istemplatekind(channel_ind, "*")) {
		ies[next_idx] := *;
		next_idx := next_idx + 1;
	} else if (not istemplatekind(channel_ind, "omit")) {
		ies[next_idx] := tr_CbspChannelInd(channel_ind);
		next_idx := next_idx + 1;
	}
	return tr_CBSP(CBSP_MSGT_KILL_COMPL, ies);
}

/* 8.1.3.6 KILL FAILURE */
function ts_CBSP_KILL_FAIL(template (value) uint16_t msg_id, template (value) uint16_t old_ser_nr,
			   template (value) CBSP_FailureListItems fail_list,
			   template (omit) CBSP_IE_NumBcastComplList compl_list,
			   template (omit) BSSMAP_FIELD_CellIdentificationList cell_list,
			   template (omit) uint8_t channel_ind)
return template (value) CBSP_PDU {
	var template (value) CBSP_IEs ies := {
		ts_CbspMsgId(msg_id),
		ts_OldSerNo(old_ser_nr),
		ts_CbspFailList(fail_list)
	};
	if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspNumComplList(valueof(compl_list));
	}
	if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := ts_CbspCellList(valueof(cell_list));
	}
	if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := ts_CbspChannelInd(channel_ind);
	}
	return ts_CBSP(CBSP_MSGT_KILL_FAIL, ies);
}
function tr_CBSP_KILL_FAIL(template uint16_t msg_id := ?, template uint16_t old_ser_nr := ?,
			   template CBSP_FailureListItems fail_list := ?,
			   template CBSP_IE_NumBcastComplList compl_list := *,
			   template BSSMAP_FIELD_CellIdentificationList cell_list := *,
			   template uint8_t channel_ind := *)
return template CBSP_PDU {
	var template CBSP_IEs ies := {
		tr_CbspMsgId(msg_id),
		tr_OldSerNo(old_ser_nr),
		tr_CbspFailList(fail_list)
	};
	if (istemplatekind(compl_list, "*")) {
		//ies[lengthof(ies)] := tr_CbspNumComplList ifpresent;
	} else if (not istemplatekind(compl_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspNumComplList(compl_list);
	}
	if (istemplatekind(cell_list, "*")) {
		//ies[lengthof(ies)] := tr_CbspCellList ifpresent;
	} else if (not istemplatekind(cell_list, "omit")) {
		ies[lengthof(ies)] := tr_CbspCellList(cell_list);
	}
	if (istemplatekind(channel_ind, "*")) {
		testcase.stop("TITAN > 6.5.0 doesn't support this");
		//ies[lengthof(ies)] := tr_CbspChannelInd(?) ifpresent;
	} else if (not istemplatekind(channel_ind, "omit")) {
		ies[lengthof(ies)] := tr_CbspChannelInd(channel_ind);
	}
	return tr_CBSP(CBSP_MSGT_KILL_FAIL, ies);
}


/* 8.1.3.16 RESET */
template (value) CBSP_PDU ts_CBSP_RESET(template (value) BSSMAP_FIELD_CellIdentificationList cell_list) :=
	ts_CBSP(CBSP_MSGT_RESET, {
			ts_CbspCellList(cell_list)
		});
template CBSP_PDU tr_CBSP_RESET(template BSSMAP_FIELD_CellIdentificationList cell_list := ?) :=
	tr_CBSP(CBSP_MSGT_RESET, {
			tr_CbspCellList(cell_list)
		});

/* 8.1.3.17 RESET COMPLETE */
template (value) CBSP_PDU ts_CBSP_RESET_COMPL(template (value) BSSMAP_FIELD_CellIdentificationList cell_list) :=
	ts_CBSP(CBSP_MSGT_RESET_COMPL, {
			ts_CbspCellList(cell_list)
		});
template CBSP_PDU tr_CBSP_RESET_COMPL(template BSSMAP_FIELD_CellIdentificationList cell_list := ?) :=
	tr_CBSP(CBSP_MSGT_RESET_COMPL, {
			tr_CbspCellList(cell_list)
		});

/* 8.1.3.18 RESET FAILURE */
template (value) CBSP_PDU ts_CBSP_RESET_FAIL(template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
					     template (value) CBSP_FailureListItems fail_items) :=
	ts_CBSP(CBSP_MSGT_RESET_FAIL, {
			ts_CbspFailList(fail_items),
			ts_CbspCellList(cell_list)
		});

template CBSP_PDU tr_CBSP_RESET_FAIL(template BSSMAP_FIELD_CellIdentificationList cell_list,
				     template CBSP_FailureListItems fail_items) :=
	tr_CBSP(CBSP_MSGT_RESET_FAIL, {
			tr_CbspFailList(fail_items),
			tr_CbspCellList(cell_list)
		});

/* 8.1.3.18a KEEP-ALIVE */
template (value) CBSP_PDU ts_CBSP_KEEP_ALIVE(uint8_t rep_period) :=
	ts_CBSP(CBSP_MSGT_KEEP_ALIVE, {ts_CbspKARepPeriod(rep_period)});
template CBSP_PDU tr_CBSP_KEEP_ALIVE(template uint8_t rep_period := ?) :=
	tr_CBSP(CBSP_MSGT_KEEP_ALIVE, {tr_CbspKARepPeriod(rep_period)});

/* 8.1.3.18b KEEP-ALIVE COMPLETE */
template (value) CBSP_PDU ts_CBSP_KEEP_ALIVE_COMPL :=
	ts_CBSP(CBSP_MSGT_KEEP_ALIVE_COMPL, {});
template CBSP_PDU tr_CBSP_KEEP_ALIVE_COMPL :=
	tr_CBSP(CBSP_MSGT_KEEP_ALIVE_COMPL, {});

/* 8.1.3.19 RESTART */
template (value) CBSP_PDU ts_CBSP_RESTART(template (value) BSSMAP_FIELD_CellIdentificationList cell_list,
					  template (value) CBSP_BcastMsgType msg_type,
					  template (value) CBSP_RecoveryInd rec_ind) :=
	ts_CBSP(CBSP_MSGT_RESTART, {
			ts_CbspCellList(cell_list),
			ts_CbspBcastMsgType(msg_type),
			ts_CbspRecoveryInd(rec_ind)
		});
template CBSP_PDU tr_CBSP_RESTART(template BSSMAP_FIELD_CellIdentificationList cell_list := ?,
				  template CBSP_BcastMsgType msg_type := ?,
				  template CBSP_RecoveryInd rec_ind := ?) :=
	tr_CBSP(CBSP_MSGT_RESTART, {
			tr_CbspCellList(cell_list),
			tr_CbspBcastMsgType(msg_type),
			tr_CbspRecoveryInd(rec_ind)
		});

/* 8.1.3.20 FAILURE */
template (value) CBSP_PDU ts_CBSP_FAILURE(template (value) CBSP_FailureListItems fail_list,
					  template (value) CBSP_BcastMsgType msg_type) :=
	ts_CBSP(CBSP_MSGT_FAILURE, {
			ts_CbspFailList(fail_list),
			ts_CbspBcastMsgType(msg_type)
		});
template CBSP_PDU tr_CBSP_FAILURE(template CBSP_FailureListItems fail_list := ?,
				  template CBSP_BcastMsgType msg_type := ?) :=
	tr_CBSP(CBSP_MSGT_FAILURE, {
			tr_CbspFailList(fail_list),
			tr_CbspBcastMsgType(msg_type)
		});

/* 8.1.3.21 ERROR INDICATION */
template (value) CBSP_PDU ts_CBSP_ERROR_IND(CBSP_Cause cause) :=
	ts_CBSP(CBSP_MSGT_ERROR_IND, {ts_CbspCause(cause)});
template CBSP_PDU tr_CBSP_ERROR_IND(template CBSP_Cause cause) :=
	tr_CBSP(CBSP_MSGT_ERROR_IND, {tr_CbspCause(cause), *});


function f_cbsp_find_ie(CBSP_PDU msg, CBSP_IEI iei, out CBSP_IE ret) return boolean {
	for (var integer i := 0; i < sizeof(msg.ies); i := i+1) {
		if (msg.ies[i].iei == iei) {
			ret := msg.ies[i];
			return true;
		}
	}
	return false;
}


}
