/*  SIMULINK2.H - Include file for making MEX-file systems and blocks
 *              with variables passed down from the workspace.
 *
 *  This file should be included at the end of a MEX-file system.
 *  It performs an interface to the MEX-file mechanism which allows 
 *  blocks and systems to be entered only as their corresponding 
 *  mathematical functions.   
 * 
 *  This template performs all checks for sizes of paramaters.
 *  With this include file you can pass down parameters from the 
 *  workspace to the system. (See for example stspace.c ).
 *
 *
 *      Syntax  of MEX-file S-function:
 *
 *     [sys, x0] = filename(t,x,u,flag)

 *  Andrew Grace  Oct 11, 1990
 *  Copyright (c) 1990-93 The Mathworks, Inc.
 *  All Rights Reserved
 */


/* Input arguments */
#define T_IN    prhs[0]
#define X_IN    prhs[1]
#define U_IN    prhs[2]
#define FLAG_IN prhs[3]

#ifdef NO_COEFF
/* NCOEFFS now replaces the number of external parameters in simulink.h */
#define NCOEFFS NO_COEFF
#endif


/* Output Arguments */

#define SYS_OUT plhs[0]
#define X0_OUT  plhs[1]


#ifdef __STDC__
void mexFunction(int nlhs, Matrix *plhs[], int nrhs, Matrix *prhs[])
#else
mexFunction(nlhs, plhs, nrhs, prhs)
int nlhs, nrhs; Matrix *plhs[], *prhs[];
#endif /* __STDC__ */
{
	int flag, i;
	double *pr;

	/* Check validity of arguments */

	if (nlhs > 2 || nrhs != 4 + NCOEFFS) {
		mexErrMsgTxt("System MEX file called with wrong number of arguments. ");
	}
	if (mxGetM(FLAG_IN) != 1 || mxGetN(FLAG_IN) != 1) {
		mexErrMsgTxt("FLAG must be a scalar in System MEX file.");
	}
	flag = (int) mxGetPr(FLAG_IN)[0];

/* Load coeffiencts into global matrix structure */
	for (i=0; i<NCOEFFS; i++) {
		Coeffs[i] = prhs[4+i]; 
	}

	/* Special case FLAG=0 return sizes and initial conditions */
	if (flag==0) {
		initialize();
		SYS_OUT = mxCreateFull(6, 1, REAL);
		pr = (double *)mxGetPr(SYS_OUT);
		pr[0] = NSTATES;
		pr[1] = NDSTATES;
		pr[2] = NOUTPUTS;
		pr[3] = NINPUTS;
		pr[4] = NSING;
		pr[5] = NEEDINPUTS;
		if (nlhs >1) {
			X0_OUT = mxCreateFull(NSTATES + NDSTATES, 1, REAL);
			init_conditions(mxGetPr(X0_OUT));
		}
		return;
	}
	if (nlhs >= 0) {
	        if (nlhs > 1) {
		        mexErrMsgTxt("System MEX file called with wrong number of output arguments. ");
		}
		/* Error checking - ommitted for speed 
		   - but may cuase segmentation faults if
		   called with the wrong sizes of arguments */
		if (mxGetM(X_IN)*mxGetN(X_IN) != NSTATES + NDSTATES) {
		        mexErrMsgTxt("State vector X wrong size in System MEX file.");
		}
		if (mxGetM(U_IN)*mxGetN(U_IN) != NINPUTS) {
			mexErrMsgTxt("Input vector U wrong size in System MEX file.");
		}
		if (mxGetM(T_IN) != 1 || mxGetN(T_IN) != 1) {
			mexErrMsgTxt("T must be a scalar in System MEX file.");
		}
	 }
	switch (flag) { 
	case 1:
	case -1:
	        if (nlhs >= 0)
		        SYS_OUT = mxCreateFull(NSTATES, 1, REAL);
		derivatives(*mxGetPr(T_IN), mxGetPr(X_IN), mxGetPr(U_IN), mxGetPr(SYS_OUT)); 
		break; 
	case 2:
	case -2:
	        if (nlhs >= 0)
		        SYS_OUT = mxCreateFull(NDSTATES, 1, REAL);
		dstates(*mxGetPr(T_IN), mxGetPr(X_IN), mxGetPr(U_IN), mxGetPr(SYS_OUT)); 
		break; 
	case 3:
	        if (nlhs >= 0)
		        SYS_OUT = mxCreateFull(NOUTPUTS, 1, REAL);
		outputs(*mxGetPr(T_IN), mxGetPr(X_IN), mxGetPr(U_IN), mxGetPr(SYS_OUT)); 
		break; 
	case 4:
	        if (nlhs >= 0) {
		        SYS_OUT = mxCreateFull(1, 1, REAL);
		        *mxGetPr(SYS_OUT) = 1e30; /* Defaults to very large number */
		}
		tnext(*mxGetPr(T_IN), mxGetPr(X_IN), mxGetPr(U_IN), mxGetPr(SYS_OUT)); 
		break; 
	case 5:
	        if (nlhs >= 0)
		       SYS_OUT = mxCreateFull(NSING, 1, REAL);
		singularity(*mxGetPr(T_IN), mxGetPr(X_IN), mxGetPr(U_IN), mxGetPr(SYS_OUT)); 
		break; 
	default:
		mexErrMsgTxt("Not a valid flag number for MEX System.");
		break;
	}
}
	


