/* $Revision: 1.12 $ */
/*  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 1990-2000 The MathWorks, Inc.
 */


/* 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]


void mexFunction(int nlhs, Matrix *plhs[], int nrhs, Matrix *prhs[])
{
    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;
    }
}
	


