/* Process model C form file: acb_fifo_jhu.pr.c */
/* Portions of this file copyright 1992, 1996, 1998 by MIL 3, Inc. */



/* This variable carries the header into the object file */
static const char acb_fifo_jhu_pr_c [] = "MIL_3_Tfile_Hdr_ 60L 30A op_runsim 7 37A72A4D 37A72A4D 1 barley jorgev 0 0 none none 0 0 none 0 0 0 0 0 0";


/* OPNET system definitions */
#include <opnet.h>

#if defined (__cplusplus)
extern "C" {
#endif
FSM_EXT_DECS
#if defined (__cplusplus)
} /* end of 'extern "C"' */
#endif


/* Header Block */

#define QUEUE_EMPTY     (op_q_empty ())
#define SVC_COMPLETION  op_intrpt_type () == OPC_INTRPT_SELF
#define ARRIVAL         op_intrpt_type () == OPC_INTRPT_STRM

/* End of Header Block */


#if !defined (VOSD_NO_FIN)
#undef	BIN
#undef	BOUT
#define	BIN		_fstack_local_info.last_line_passed = __LINE__ - _block_origin;
#define	BOUT	BIN
#define	BINIT	_fstack_local_info.last_line_passed = 0; _block_origin = __LINE__;
#else
#define	BINIT
#endif /* #if !defined (VOSD_NO_FIN) */



/* State variable definitions */
typedef struct
	{
	/* Internal state tracking for FSM */
	FSM_SYS_STATE
	/* State Variables */
	int	                    		server_busy;
	double	                 		service_rate;
	Objid	                  		own_id;
	int	                    		in_pk_count;
	Stathandle	             		in_pk_cnt_stathandle;
	int	                    		out_pk_count;
	Stathandle	             		out_pk_cnt_stathandle;
	} acb_fifo_jhu_state;

#define pr_state_ptr            		((acb_fifo_jhu_state*) SimI_Mod_State_Ptr)
#define server_busy             		pr_state_ptr->server_busy
#define service_rate            		pr_state_ptr->service_rate
#define own_id                  		pr_state_ptr->own_id
#define in_pk_count             		pr_state_ptr->in_pk_count
#define in_pk_cnt_stathandle    		pr_state_ptr->in_pk_cnt_stathandle
#define out_pk_count            		pr_state_ptr->out_pk_count
#define out_pk_cnt_stathandle   		pr_state_ptr->out_pk_cnt_stathandle

/* This macro definition will define a local variable called	*/
/* "op_sv_ptr" in each function containing a FIN statement.	*/
/* This variable points to the state variable data structure,	*/
/* and can be used from a C debugger to display their values.	*/
#undef FIN_PREAMBLE
#define FIN_PREAMBLE	acb_fifo_jhu_state *op_sv_ptr = pr_state_ptr;


/* No Function Block */

enum { _block_origin = __LINE__ };

#if defined (__cplusplus)
extern "C" {
#endif
	void acb_fifo_jhu (void);
	Compcode acb_fifo_jhu_init (void **);
	void acb_fifo_jhu_diag (void);
	void acb_fifo_jhu_terminate (void);
	void acb_fifo_jhu_svar (void *, const char *, char **);
#if defined (__cplusplus)
} /* end of 'extern "C"' */
#endif




/* Process model interrupt handling procedure */


void
acb_fifo_jhu (void)
	{
	int _block_origin = 0;
	FIN (acb_fifo_jhu ());
	if (1)
		{
		Packet*          pkptr;
		int             pk_len;
		double          pk_svc_time;
		int             insert_ok;


		FSM_ENTER (acb_fifo_jhu)

		FSM_BLOCK_SWITCH
			{
			/*---------------------------------------------------------*/
			/** state (init) enter executives **/
			FSM_STATE_ENTER_FORCED (0, state0_enter_exec, "init", "acb_fifo_jhu () [init enter execs]")
				{
				/* initially the server is idle 	*/
				server_busy = 0;
				
				/* get queue module's own object id	*/
				own_id = op_id_self ();
				  						
				/* get assigned value of server 	*/
				/* processing rate 					*/
				op_ima_obj_attr_get (own_id, "service_rate", &service_rate);
				
				/* initialize packet counters */
				in_pk_count  = 0;
				out_pk_count = 0;
				
				/* register packet counter statistic */
				in_pk_cnt_stathandle = op_stat_reg ("incoming packet count",
				     OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
				out_pk_cnt_stathandle = op_stat_reg ("outgoing packet count",
				     OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
				}


			/** state (init) exit executives **/
			FSM_STATE_EXIT_FORCED (0, state0_exit_exec, "init", "acb_fifo_jhu () [init exit execs]")
				{
				}


			/** state (init) transition processing **/
			FSM_INIT_COND (ARRIVAL)
			FSM_DFLT_COND
			FSM_TEST_LOGIC ("init")

			FSM_TRANSIT_SWITCH
				{
				FSM_CASE_TRANSIT (0, 1, state1_enter_exec, ;)
				FSM_CASE_TRANSIT (1, 2, state2_enter_exec, ;)
				}
				/*---------------------------------------------------------*/



			/** state (arrival) enter executives **/
			FSM_STATE_ENTER_FORCED (1, state1_enter_exec, "arrival", "acb_fifo_jhu () [arrival enter execs]")
				{
				/* acquire the arriving packet 				*/
				/* multiple arriving streams are supported. */
				pkptr = op_pk_get (op_intrpt_strm ());
				
				/* update incoming packets counter */
				in_pk_count = in_pk_count + 1;
				op_stat_write (in_pk_cnt_stathandle, in_pk_count);
				
				/* attempt to enqueue the packet at tail 	*/
				/* of subqueue 0.							*/
				if (op_subq_pk_insert (0, pkptr, OPC_QPOS_TAIL) != OPC_QINS_OK)
				    {
				    /* the inserton failed (due to to a 	*/
					/* full queue) deallocate the packet.	*/
				    op_pk_destroy (pkptr);
				
					/* set flag indicating insertion fail 	*/
					/* this flag is used to determine 		*/
					/* transition out of this state 		*/
				    insert_ok = 0;
				    }
				else{
					/* insertion was successful 			*/
				    insert_ok = 1;
				    }
				
				
				}


			/** state (arrival) exit executives **/
			FSM_STATE_EXIT_FORCED (1, state1_exit_exec, "arrival", "acb_fifo_jhu () [arrival exit execs]")
				{
				}


			/** state (arrival) transition processing **/
			FSM_INIT_COND (!server_busy && insert_ok)
			FSM_DFLT_COND
			FSM_TEST_LOGIC ("arrival")

			FSM_TRANSIT_SWITCH
				{
				FSM_CASE_TRANSIT (0, 3, state3_enter_exec, ;)
				FSM_CASE_TRANSIT (1, 2, state2_enter_exec, ;)
				}
				/*---------------------------------------------------------*/



			/** state (idle) enter executives **/
			FSM_STATE_ENTER_UNFORCED (2, state2_enter_exec, "idle", "acb_fifo_jhu () [idle enter execs]")
				{
				}


			/** blocking after enter executives of unforced state. **/
			FSM_EXIT (5,acb_fifo_jhu)


			/** state (idle) exit executives **/
			FSM_STATE_EXIT_UNFORCED (2, state2_exit_exec, "idle", "acb_fifo_jhu () [idle exit execs]")
				{
				}


			/** state (idle) transition processing **/
			FSM_INIT_COND (ARRIVAL)
			FSM_TEST_COND (SVC_COMPLETION)
			FSM_TEST_LOGIC ("idle")

			FSM_TRANSIT_SWITCH
				{
				FSM_CASE_TRANSIT (0, 1, state1_enter_exec, ;)
				FSM_CASE_TRANSIT (1, 4, state4_enter_exec, ;)
				}
				/*---------------------------------------------------------*/



			/** state (svc_start) enter executives **/
			FSM_STATE_ENTER_FORCED (3, state3_enter_exec, "svc_start", "acb_fifo_jhu () [svc_start enter execs]")
				{
				/* get a handle on packet at head of subqueue 0 */
				/* (this does not remove the packet) 			*/
				pkptr = op_subq_pk_access (0, OPC_QPOS_HEAD);
				
				/* determine the packets length (in bits) 		*/
				pk_len = op_pk_total_size_get (pkptr);
				
				/* determine the time required to complete 		*/
				/* service of the packet 						*/
				pk_svc_time = pk_len / service_rate;
				
				/* schedule an interrupt for this process 		*/
				/* at the time where service ends. 				*/
				op_intrpt_schedule_self (op_sim_time () + pk_svc_time, 0);
				
				/* the server is now busy. 						*/
				server_busy = 1;
				
				
				}


			/** state (svc_start) exit executives **/
			FSM_STATE_EXIT_FORCED (3, state3_exit_exec, "svc_start", "acb_fifo_jhu () [svc_start exit execs]")
				{
				}


			/** state (svc_start) transition processing **/
			FSM_TRANSIT_FORCE (2, state2_enter_exec, ;)
				/*---------------------------------------------------------*/



			/** state (svc_compl) enter executives **/
			FSM_STATE_ENTER_FORCED (4, state4_enter_exec, "svc_compl", "acb_fifo_jhu () [svc_compl enter execs]")
				{
				/* extract packet at head of queue; this	*/
				/* is the packet just finishing service 	*/
				pkptr = op_subq_pk_remove (0, OPC_QPOS_HEAD);
				
				/* update outcoming packets counter */
				out_pk_count = out_pk_count + 1;
				op_stat_write (out_pk_cnt_stathandle, out_pk_count);
				
				/* forward the packet on stream 0, causing 	*/
				/* an immediate interrupt at destination.	*/
				op_pk_send_forced (pkptr, 0);
				
				/* server is idle again. 					*/
				server_busy = 0;
				}


			/** state (svc_compl) exit executives **/
			FSM_STATE_EXIT_FORCED (4, state4_exit_exec, "svc_compl", "acb_fifo_jhu () [svc_compl exit execs]")
				{
				}


			/** state (svc_compl) transition processing **/
			FSM_INIT_COND (!QUEUE_EMPTY)
			FSM_DFLT_COND
			FSM_TEST_LOGIC ("svc_compl")

			FSM_TRANSIT_SWITCH
				{
				FSM_CASE_TRANSIT (0, 3, state3_enter_exec, ;)
				FSM_CASE_TRANSIT (1, 2, state2_enter_exec, ;)
				}
				/*---------------------------------------------------------*/



			}


		FSM_EXIT (0,acb_fifo_jhu)
		}
	}


Compcode
acb_fifo_jhu_init (void ** gen_state_pptr)
	{
	int _block_origin = 0;
	static VosT_Cm_Obtype	obtype = OPC_NIL;

	extern void				Vos_Vnop (void);

	FIN (acb_fifo_jhu_init (gen_state_pptr))

	if (obtype == OPC_NIL)
		{
		/* Initialize memory management */
		if (Vos_Catmem_Register ("proc state vars (acb_fifo_jhu)",
			sizeof (acb_fifo_jhu_state), Vos_Vnop, &obtype) == VOSC_FAILURE)
			{
			FRET (OPC_COMPCODE_FAILURE)
			}
		}

	*gen_state_pptr = Vos_Catmem_Alloc (obtype, 1);
	if (*gen_state_pptr == OPC_NIL)
		{
		FRET (OPC_COMPCODE_FAILURE)
		}
	else
		{
		/* Initialize FSM handling */
		((acb_fifo_jhu_state *)(*gen_state_pptr))->current_block = 0;

		FRET (OPC_COMPCODE_SUCCESS)
		}
	}



void
acb_fifo_jhu_diag (void)
	{
	/* No Diagnostic Block */
	}




void
acb_fifo_jhu_terminate (void)
	{
	int _block_origin = __LINE__;

	FIN (acb_fifo_jhu_terminate (void))

	if (1)
		{
		Packet*          pkptr;
		int             pk_len;
		double          pk_svc_time;
		int             insert_ok;

		/* No Termination Block */

		}
	Vos_Catmem_Dealloc (pr_state_ptr);

	FOUT;
	}


/* Undefine shortcuts to state variables to avoid */
/* syntax error in direct access to fields of */
/* local variable prs_ptr in acb_fifo_jhu_svar function. */
#undef server_busy
#undef service_rate
#undef own_id
#undef in_pk_count
#undef in_pk_cnt_stathandle
#undef out_pk_count
#undef out_pk_cnt_stathandle



void
acb_fifo_jhu_svar (void * gen_ptr, const char * var_name, char ** var_p_ptr)
	{
	acb_fifo_jhu_state		*prs_ptr;

	FIN (acb_fifo_jhu_svar (gen_ptr, var_name, var_p_ptr))

	*var_p_ptr = (char *)VOS_NIL;
	prs_ptr = (acb_fifo_jhu_state *)gen_ptr;

	if (Vos_String_Equal ("server_busy" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->server_busy);
		goto func_return;
		}
	if (Vos_String_Equal ("service_rate" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->service_rate);
		goto func_return;
		}
	if (Vos_String_Equal ("own_id" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->own_id);
		goto func_return;
		}
	if (Vos_String_Equal ("in_pk_count" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->in_pk_count);
		goto func_return;
		}
	if (Vos_String_Equal ("in_pk_cnt_stathandle" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->in_pk_cnt_stathandle);
		goto func_return;
		}
	if (Vos_String_Equal ("out_pk_count" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->out_pk_count);
		goto func_return;
		}
	if (Vos_String_Equal ("out_pk_cnt_stathandle" , var_name))
		{
		*var_p_ptr = (char *) (&prs_ptr->out_pk_cnt_stathandle);
		goto func_return;
		}

func_return:

	FOUT;
	}

