module RAN_Adapter {

/* This module implements a 'dumb' RAN adapter.  It creates the M3UA and SCCP components and stacks a
 * BSSAP/RANAP codec port on top.  As a result, it provides the ability to transceive SCCP-User-SAP primitives
 * with deoded BSSAP/RANAP payload.  Use this if you want to have full control about what you transmit or
 * receive, without any automatisms in place.  Allows you to refuse connections or other abnormal behavior. */

/* (C) 2017-2019 Harald Welte <laforge@gnumonks.org>
 * contributions by sysmocom - s.f.m.c. GmbH
 * 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
 */

import from General_Types all;
import from Osmocom_Types all;

import from M3UA_Emulation all;
import from MTP3asp_Types all;
import from MTP3asp_PortType all;

import from SCCP_Types all;
import from SCCPasp_Types all;
import from SCCP_Emulation all;
import from SCCP_Templates all;

import from SCCP_Adapter all;

#ifdef RAN_EMULATION_BSSAP
import from BSSMAP_Templates all;
#endif
import from RAN_Emulation all;

type record RAN_Adapter {
	SCCP_Adapter sccpa,
	RAN_Transport transport,
	RAN_Emulation_CT vc_RAN
}

type record RAN_Configuration {
	RAN_Transport transport,
	SCCP_Adapter_Config sccp
};
type record of RAN_Configuration RAN_Configurations;

function f_ran_adapter_init(inout RAN_Adapter ba, in RAN_Configuration cfg, charstring id,
			    RanOps ops) {
	f_sccp_adapter_init(ba.sccpa, cfg.sccp, id);
	ba.transport := cfg.transport;
	ops.sccp_addr_local := ba.sccpa.sccp_addr_own;
	ops.sccp_addr_peer := ba.sccpa.sccp_addr_peer;

	/* create components */
	ba.vc_RAN := RAN_Emulation_CT.create(id & "-RAN") alive;

	timer T := 5.0;
	T.start;
	//T.timeout;
	ops.transport := cfg.transport;
	/* connect BSSNAP component to upper side of SCCP */
	if (cfg.transport == RANAP_TRANSPORT_IuCS) {
#ifdef RAN_EMULATION_RANAP
		log("Connecting RANAP RAN_Emulation to SCCP_SP_PORT");
		ops.protocol := RAN_PROTOCOL_RANAP
		connect(ba.vc_RAN:RANAP, ba.sccpa.vc_SCCP:SCCP_SP_PORT);
#endif
	} else {
#ifdef RAN_EMULATION_BSSAP
		log("Connecting BSSAP RAN_Emulation to SCCP_SP_PORT");
		connect(ba.vc_RAN:BSSAP, ba.sccpa.vc_SCCP:SCCP_SP_PORT);
#endif
	}
	if (cfg.transport == BSSAP_TRANSPORT_SCCPlite) {
#ifdef IPA_EMULATION_MGCP
		/* connect IPA MGCP port with BSSMAP MGCP port */
		log("Connecting MGCP RAN Emulation to IPA MGCP PORT");
		connect(ba.sccpa.vc_IPA:IPA_MGCP_PORT, ba.vc_RAN:MGCP);
#endif
#ifdef IPA_EMULATION_CTRL
#ifdef RAN_EMULATION_CTRL
		/* connect IPA CTRL port with BSSMAP CTRL port */
		log("Connecting CTRL RAN Emulation to IPA CTRL PORT");
		connect(ba.sccpa.vc_IPA:IPA_CTRL_PORT, ba.vc_RAN:CTRL);
#endif
#endif
	}
	log("Starting RAN_Emulation");
	ba.vc_RAN.start(RAN_Emulation.main(valueof(ops), ""));
}

function f_ran_adapter_start(inout RAN_Adapter ba) {
	f_sccp_adapter_start(ba.sccpa);
}

function f_ran_adapter_cleanup(inout RAN_Adapter ba) {
	if (ba.transport == RANAP_TRANSPORT_IuCS) {
#ifdef RAN_EMULATION_RANAP
		disconnect(ba.vc_RAN:RANAP, ba.sccpa.vc_SCCP:SCCP_SP_PORT);
#endif
	} else {
#ifdef RAN_EMULATION_BSSAP
		disconnect(ba.vc_RAN:BSSAP, ba.sccpa.vc_SCCP:SCCP_SP_PORT);
#endif
	}
	ba.vc_RAN.stop;

	f_sccp_adapter_cleanup(ba.sccpa);
}


}
