/* Copyright 1990-2000 The MathWorks, Inc. 
 *
 * File    : simulink.c                                  $Revision: 1.76 $
 * Abstract:
 *      Epilog C include file used when compiling MEX-file S-functions.
 *
 *      This file should be included at the end of a MEX-file system.  It
 *      provides an interface to the MEX-file mechanism that allows blocks
 *      and systems to be entered only as their corresponding mathematical
 *      functions without the need for addition interface code
 *
 *      All local functions and defines begin with an underscore "_" to help
 *      in avoiding name conflicts with user functions and defines.
 *
 *      This file supports both level 1 and level 2 S-functions.
 */

#undef   printf   /* don't want to redefine mexPrintf! */
#include <stdio.h>

/*LINTLIBRARY*/

/*==============================*
 * Pre-processor error checking *
 *==============================*/

#ifndef S_FUNCTION_NAME
#error S_FUNCTION_NAME must be defined
#endif

#if defined(_S_FUNCTION_NAME_NOT_DEFINED_BEFORE_SIMSTRUCT)
#error S_FUNCTION_NAME must be defined before include of simstruc.h
#endif

#if S_FUNCTION_LEVEL == 2
# if defined(MDL_GET_INPUT_PORT_WIDTH)
#   error mdlGetInputPortWidth(S,outputWidth) cannot be used in \
        level 2 S-functions see mdlSetInputPortWidth(S,port,width) and \
        mdlSetOutputPortWidth(S,port,width)
# endif
# if defined(MDL_GET_OUTPUT_PORT_WIDTH)
#   error mdlGetOutputPortWidth(S,inputWidth) cannot be used in \
        level 2 S-functions see mdlSetInputPortWidth(S,port,width) and \
        mdlSetOutputPortWidth(S,port,width)
# endif


# if (defined(MDL_SET_INPUT_PORT_WIDTH) || \
      defined(MDL_SET_OUTPUT_PORT_WIDTH)) && \
     (defined(MDL_SET_INPUT_PORT_DIMENSION_INFO) || \
      defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO))
#   error Cannot use mdlSetInput(Output)PortWidth \
and mdlSetInput(Output)PortDimensionInfo at the same time in an S-function; \
Use either a width or dimension method, but not both

#endif
#endif

/*=========*
 * Defines *
 *=========*/

#define _QUOTE1(name) #name
#define _QUOTE(name) _QUOTE1(name)   /* need to expand name */


#define _LHS_RET    0    /* return (sizes, derivs, dstates, output, tnext)   */
#define _LHS_X0     1    /* initial state conditions                         */
#define _LHS_STR    2    /* state strings                                    */
#define _LHS_TS     3    /* sample times (sampling period, offset)           */
#define _LHS_XTS    4    /* state sample times (sampling period, offset)     */

#define _LHS_SS     1    /* Pointer to SimStruct if (nlhs < 0)               */

#define _RHS_T      0    /* Time                                             */
#define _RHS_X      1    /* States                                           */
#define _RHS_U      2    /* Inputs                                           */
#define _RHS_FLAG   3    /* mode flag                                        */


#define _GetNumEl(pm) (mxGetM(pm)*mxGetN(pm))


/*===========================*
 * Data local to this module *
 *===========================*/

static char_T _sfcnName[] = "MEX level" _QUOTE(S_FUNCTION_LEVEL) 
     " S-function \"" _QUOTE(S_FUNCTION_NAME) "\"";


const DimsInfo_T DYNAMIC_DIMENSION_DEF = {-1, -1, NULL, NULL}; 
const DimsInfo_T *DYNAMIC_DIMENSION    = &DYNAMIC_DIMENSION_DEF;

/*===================*
 * Private functions *
 *===================*/


#ifndef MDL_ZERO_CROSSINGS
  /* Function: mdlZeroCrossings ===============================================
   * Abstract:
   *    This routine is present for S-functions which register that they
   *    have nonsampled zero crossings, but don't register this routine.
   */
  static void mdlZeroCrossings(SimStruct *S)
  {
      ssSetErrorStatus(S,
                       "To have nonsampled zero crossings, you must define "
                       "MDL_ZERO_CROSSINGS and have a "
                       "mdlZeroCrossings routine");
      return;
  }
#endif


#ifndef MDL_GET_TIME_OF_NEXT_VAR_HIT
  /* Function: mdlGetTimeOfNextVarHit =========================================
   * Abstract:
   *    This routine is present for backwards compatibility with
   *    Simulink 1.3 S-function which didn't have mdlGetTimeOfNextVarHit
   */
  static void mdlGetTimeOfNextVarHit(SimStruct *S)
  {
      ssSetErrorStatus(S,
                       "To have a variable sample time, "
                       "you must define MDL_GET_TIME_OF_NEXT_VAR_HIT "
                       "and add a mdlGetTimeOfNextVarHit routine");
      return;
  } /* end mdlGetTimeOfNextVarHit */
#endif


#if S_FUNCTION_LEVEL==2
/* Function: _RegNumInputPortsCB ==============================================
 * Abstract:
 *      Called by a level 2 S-function during mdlInitializeSizes.
 *
 * Returns:
 *      1  - register was successful
 *      0 - register was not successful
 */
static int_T _RegNumInputPortsCB(void *Sptr, int_T nInputPorts) {
    SimStruct *S = (SimStruct *)Sptr;

    if (nInputPorts < 0) {
        return(0);
    }

    _ssSetNumInputPorts(S,nInputPorts);
    _ssSetSfcnUsesNumPorts(S, 1);

    if (nInputPorts > 0) {
        ssSetPortInfoForInputs(S,
           (struct _ssPortInputs*)mxCalloc((size_t)nInputPorts,
                                           sizeof(struct _ssPortInputs)));
    }

    return(1);

} /* end _RegNumInputPortsCB */



/* Function: _RegNumOutputPortsCB =============================================
 * Abstract:
 *      Called by a level 2 S-function during mdlInitializeSizes.
 *
 * Returns:
 *      1  - register was successful
 *      0 - register was not successful
 */
static int_T _RegNumOutputPortsCB(void *Sptr, int_T nOutputPorts) {
    SimStruct *S = (SimStruct *)Sptr;

    if (nOutputPorts < 0) {
        return(0);
    }

    _ssSetNumOutputPorts(S,nOutputPorts);
    _ssSetSfcnUsesNumPorts(S, 1);

    if (nOutputPorts > 0) {
        ssSetPortInfoForOutputs(S,
            (struct _ssPortOutputs*)mxCalloc((size_t)nOutputPorts,
                                             sizeof(struct _ssPortOutputs)));
    }

    return(1);

} /* end _RegNumOutputPortsCB */

/* Function:  _ssSetInputPortMatrixDimensions ===================================
 * Returns:
 *      1 - set was successful
 *      0 - set was not successful
 */
int_T _ssSetInputPortMatrixDimensions(SimStruct *S, int_T port, int_T m, int_T n)
{   
    int_T      status;
    DimsInfo_T dimsInfo = *DYNAMIC_DIMENSION;
    int_T      dims[2];
    
    dims[0]            = m;
    dims[1]            = n;
    
    dimsInfo.numDims   = 2;
    dimsInfo.dims      = dims;
    dimsInfo.width     = ((m == DYNAMICALLY_SIZED) || (n == DYNAMICALLY_SIZED))?
                           DYNAMICALLY_SIZED : (m * n);
  
    status = ssSetInputPortDimensionInfo(S, port, &dimsInfo);

    return(status);
} /* end _ssSetInputPortMatrixDimensions */


/* Function:  _ssSetOutputPortMatrixDimensions ====================================
 * Returns:
 *      1 - set was successful
 *      0 - set was not successful
 */
int_T _ssSetOutputPortMatrixDimensions(SimStruct *S, int_T port, int_T m, int_T n)
{   
    int_T      status;
    DimsInfo_T dimsInfo = *DYNAMIC_DIMENSION;
    int_T      dims[2];

    dims[0]            = m;
    dims[1]            = n;

    dimsInfo.numDims   = 2;
    dimsInfo.dims      = dims;
    dimsInfo.width     = ((m == DYNAMICALLY_SIZED) || (n == DYNAMICALLY_SIZED))?
                           DYNAMICALLY_SIZED : (m * n);

    status = ssSetOutputPortDimensionInfo(S, port, &dimsInfo);

    return(status);
} /* end _ssSetOutputPortMatrixDimensions */

/* Function:  _ssSetInputPortVectorDimension ====================================
 * Returns:
 *      1 - set was successful
 *      0 - set was not successful
 */
int_T _ssSetInputPortVectorDimension(SimStruct *S, int_T port, int_T m)
{   
    int_T      status;
    DimsInfo_T dimsInfo = *DYNAMIC_DIMENSION;
    
    dimsInfo.numDims   = 1;
    dimsInfo.dims      = &(dimsInfo.width);
    dimsInfo.width     = m;
  
    status = ssSetInputPortDimensionInfo(S, port, &dimsInfo);

    return(status);
} /* end _ssSetInputPortVectorDimension */


/* Function:  _ssSetOutputPortVectorDimension ====================================
 * Returns:
 *      1 - set was successful
 *      0 - set was not successful
 */
int_T _ssSetOutputPortVectorDimension(SimStruct *S, int_T port, int_T m)
{   
    int_T      status;
    DimsInfo_T dimsInfo = *DYNAMIC_DIMENSION;
    
    dimsInfo.numDims   = 1;
    dimsInfo.dims      = &(dimsInfo.width);
    dimsInfo.width     = m;

    status = ssSetOutputPortDimensionInfo(S, port, &dimsInfo);

    return(status);
} /* end _ssSetOutputPortVectorDimension */

#endif



/* Function: _CreateSimStruct =================================================
 * Abstract:
 *      Allocate the simulation structure.
 */
#ifdef V4_COMPAT /* Use MATLAB 4 prototyping */
static SimStruct *_CreateSimStruct(int_T nrhs, Matrix *prhs[])
#else
static SimStruct *_CreateSimStruct(int_T nrhs, const mxArray *prhs[])
#endif /* V4_COMPAT */
{
    int_T               nParams  = (nrhs > 4)? nrhs - 4: 0;
    SimStruct         *S       = (SimStruct *) mxCalloc((size_t)1,
                                                        sizeof(SimStruct));
    struct _ssMdlInfo *mdlInfo = 
        (struct _ssMdlInfo*) mxCalloc((size_t)1,sizeof(*mdlInfo));


    _ssSetRootSS(S, S);
    _ssSetMdlInfoPtr(S, mdlInfo);
    _ssSetSimMode(S, SS_SIMMODE_SIZES_CALL_ONLY);
    _ssSetSFcnParamsCount(S,nParams);

    _ssSetPath(S,_QUOTE(S_FUNCTION_NAME));
    _ssSetModelName(S,_QUOTE(S_FUNCTION_NAME));

    if (nParams > 0) {
        /******************************
         * Load S-function parameters *
         ******************************/
        const mxArray **ppa=(const mxArray**)mxCalloc((size_t)nParams,
                                                      sizeof(ppa[0]));
        int_T           i;

        _ssSetSFcnParamsPtr(S, ppa);

        for (i = 0; i < nParams; i++) _ssSetSFcnParam(S, i, prhs[4+i]);
    }

    /*
     * Setup to handle level 2, ssSetNum[Out|In]putPorts.
     */
#   if S_FUNCTION_LEVEL == 2
    ssSetRegNumInputPortsFcn(S, _RegNumInputPortsCB);
    ssSetRegNumInputPortsFcnArg(S, (void *)S);
    ssSetRegNumOutputPortsFcn(S, _RegNumOutputPortsCB);
    ssSetRegNumOutputPortsFcnArg(S, (void *)S);
#   endif

    return(S);

} /* end _CreateSimStruct */


/*==================*
 * Global functions *
 *==================*/

/* Function: ssGetDTypeIdFromMxArray ===========================================
 * Abstract:
 *      Utility to translate the mxClassId of an mxArray to one of Simulink's
 *      built-in data type indices. The return value is of type DTypeId, which
 *      is defined in simstruc.h
 *
 *      This function returns INVALID_DTYPE_ID if the mxClassId does not map to
 *      any built-in Simulink data type. For example, if mxId == mxSTRUCT_CLASS
 *      then the return value is INVALID_DTYPE_ID.
 *      Otherwise the return value is one of the enum values in BuiltInDTypeId.
 *      For example if mxId == mxUINT16_CLASS then the return value is SS_UINT16
 */
DTypeId ssGetDTypeIdFromMxArray(const mxArray *m)
{
    DTypeId dTypeId;
    mxClassID mxId = mxGetClassID(m);

    switch (mxId) {
      case mxCELL_CLASS:
      case mxSTRUCT_CLASS:
      case mxOBJECT_CLASS:
      case mxCHAR_CLASS:
      case mxSPARSE_CLASS:
        dTypeId = INVALID_DTYPE_ID;
        break;
      case mxDOUBLE_CLASS:
        dTypeId = SS_DOUBLE;
        break;
      case mxSINGLE_CLASS:
        dTypeId = SS_SINGLE;
        break;
      case mxINT8_CLASS:
        dTypeId = SS_INT8;
        break;
      case mxUINT8_CLASS:
        if (mxIsLogical(m)) {
            dTypeId = SS_BOOLEAN;
        } else {
            dTypeId = SS_UINT8;
        }
        break;
      case mxINT16_CLASS:
        dTypeId = SS_INT16;
        break;
      case mxUINT16_CLASS:
        dTypeId = SS_UINT16;
        break;
      case mxINT32_CLASS:
        dTypeId = SS_INT32;
        break;
      case mxUINT32_CLASS:
        dTypeId = SS_UINT32;
        break;
      case mxINT64_CLASS:
      case mxUINT64_CLASS:
      case mxUNKNOWN_CLASS:
        dTypeId = INVALID_DTYPE_ID;
        break;
      default:
        dTypeId = INVALID_DTYPE_ID;
        break;
    }
    return(dTypeId);

} /* end ssGetDTypeIdFromMxArray */


/*===============================================*
 * Global functions (can be used only in mdlRTW) *
 *===============================================*/


/* Function: ssWarning ========================================================
 * Abstract:
 *	Call mexWarnMstTxt to issue the specified warning message
 */
void ssWarning(SimStruct *S, const char *msg)
{
    const char fmt[] = "block '%s': %s";
    char *warnMsg = (ssGetPath(S) != NULL?
                     (char *)malloc(strlen(msg)+
                                    sizeof(fmt)+strlen(ssGetPath(S))+1):
                     NULL);
    if (warnMsg == NULL) {
        mexWarnMsgTxt(msg);
    } else {
        (void)sprintf(warnMsg,fmt,ssGetPath(S),msg);
        mexWarnMsgTxt(warnMsg);
        free(warnMsg);
    }
} /* end ssWarning */


/* Function: ssWriteRTWStr ====================================================
 * Abstract:
 *	Only for use in the mdlRTW method. This is a "low-level" routine
 *	for writing strings directly into the model.rtw file. It typically
 *	shouldn't be used by S-functions, unless you need to create 
 *	"sub" Block record. These records should start with SFcn to
 *	avoid future compatibility problems. For example:
 *
 *	mdlRTW()
 *	{
 *	   if (!ssWriteRTWStr(S, "SFcnMySpecialRecord {")) return;
 *	   <snip>
 *	   if (!ssWriteRTWStr(S, "}")) return;
 *      }
 *
 */
int_T ssWriteRTWStr(SimStruct *S, const char_T *str)
{
    int_T ans = 0;
#   if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#   pragma mpwc on
#   endif
    ans = (*S->mdlInfo->writeRTWStrFcn)(S->mdlInfo->writeRTWFcnArg, str);
#   if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#   pragma mpwc off
#   endif
    return(ans);

} /* end ssWriteRTWStr */


/* Function: ssWriteRTWMxVectParam =============================================
 * Abstract:
 *	Only for use in the mdlRTW method. This is a "low-level" routine for
 *      writing Matlab style vectors (could be complex valued) into the mdl.rtw
 *      file. Typically this function should not be used by S-functions, the
 *      function ssWriteRTWParamSettings is more appropriate in most cases.
 *      However, this function is useful when you are writing out custom data
 *      structures directly in the mdl.rtw file.
 */
int_T ssWriteRTWMxVectParam(SimStruct    *S,
                            const char_T *name,
                            const void   *rVal,
                            const void   *iVal,
                            int_T        dtInfo,
                            int_T        numEl)
{
    const void *pD[2];

    pD[0] = rVal;
    pD[1] = iVal;
    return( ssWriteRTWNameValuePair(S,SSWRITE_VALUE_DTYPE_ML_VECT,
                                    name, pD, dtInfo, numEl) );

} /* end ssWriteRTWMxVectParam */


/* Function: ssWriteRTWMx2dMatParam ============================================
 * Abstract:
 *	Only for use in the mdlRTW method. This is a "low-level" routine for
 *      writing Matlab style matrices (could be complex valued) into the mdl.rtw
 *      file. Typically this function should not be used by S-functions, the
 *      function ssWriteRTWParamSettings is more appropriate in most cases.
 *      However, this function is useful when you are writing out custom data
 *      structures directly in the mdl.rtw file.
 */
int_T ssWriteRTWMx2dMatParam(SimStruct    *S,
                             const char_T *name,
                             const void   *rVal,
                             const void   *iVal,
                             int_T        dtInfo,
                             int_T        nRows,
                             int_T        nCols)
{
    const void *pD[2];
    pD[0] = rVal;
    pD[1] = iVal;
    return( ssWriteRTWNameValuePair(S,SSWRITE_VALUE_DTYPE_ML_2DMAT,
                                    name, pD, dtInfo, nRows, nCols) );

} /* end ssWriteRTWMx2dMatParam */


/* Function: ssWriteRTWNameValuePair ===========================================
 * Abstract:
 *	Only for use in the mdlRTW method. This is a "low-level" routine for
 *      writing name-value pairs directly into the model.rtw file. The input
 *      arguments for this function are subject to change, therefore you should
 *      not invoke this function directly. Instead, use the ssWriteRTWxxxParam()
 *      macros documented in matlabroot/simulink/src/sfuntmpl.doc (also see
 *      matlabroot/simulink/src/ml2rtw.c for examples of usage). The macros will
 *      in turn invoke this function with the appropriate arguments. Using these
 *      macros you will be able to write custom sub-records into your S-Function
 *      block record in the .rtw file. For example:
 *
 *	   mdlRTW()
 *	   {
 *	      if (!ssWriteRTWStr(S, "SFcnMySpecialRecord {")) return;
 *	      if (!ssWriteRTWStrParam(S, SSWRITE_VALUE_STR, "MyFieldName",
 *                                         "IsVeryVeryCool")) return;
 *	      if (!ssWriteRTWStr(S, "}")) return;
 *         }
 *
 *      will create the following sub-record in the Block's record:
 *
 *         Block {
 *            :
 *            :
 *            SFcnMySpecialRecord {
 *               MyFieldName   IsVeryVeryCool
 *            }
 *            :
 *            :
 *         }
 *
 *      Beware that you can easily corrupt the model.rtw file via these macros.
 *
 * Returns:
 *     1 - success
 *     0 - error. The appropriate error message is set in ssGetErrorStatus(S)
 */
int_T ssWriteRTWNameValuePair(SimStruct    *S,
                              int_T        type,
                              const char_T *name,
                              const void   *value,
                              ...)
{
    int_T      ans        = 1;      /* assume */
    int_T      dtInfo     = 0;      /* real and double */
    int_T      nRows      = 1;
    int_T      nCols      = 1;
    int_T      haveImData = 0;      /* assume */
    int_T      haveNCols  = 0;
    const void *pValue    = NULL;

    va_list    ap;
    va_start(ap, value);
    pValue = (void *)value;

    switch (type) {
      case SSWRITE_VALUE_STR:
      case SSWRITE_VALUE_QSTR:
        /* No additional args */
        break;
      case SSWRITE_VALUE_VECT_STR:
        nRows     = va_arg(ap, int_T);  /* nItems e.g. ["a", "b", "c"] has 3 */
        break;
      case SSWRITE_VALUE_NUM:
      case SSWRITE_VALUE_DTYPE_NUM:
        dtInfo = va_arg(ap, int_T);
        break;
      case SSWRITE_VALUE_VECT:
      case SSWRITE_VALUE_DTYPE_VECT:
        dtInfo     = va_arg(ap, int_T);
        nRows      = va_arg(ap, int_T);
        break;
      case SSWRITE_VALUE_2DMAT:
      case SSWRITE_VALUE_DTYPE_2DMAT:
        dtInfo    = va_arg(ap, int_T);
        nRows     = va_arg(ap, int_T);
        nCols     = va_arg(ap, int_T);
        haveNCols = 1;
        break;
      case SSWRITE_VALUE_DTYPE_ML_VECT:
        {
            haveImData = 1;
            dtInfo     = va_arg(ap, int_T);
            nRows      = va_arg(ap, int_T);
            break;
        }
      case SSWRITE_VALUE_DTYPE_ML_2DMAT:
        {
            haveImData = 1;
            haveNCols  = 1;
            dtInfo     = va_arg(ap, int_T);
            nRows      = va_arg(ap, int_T);
            nCols      = va_arg(ap, int_T);
            break;
        }
      default:
        ssSetErrorStatus(S, "Invalid SSWRITE_VALUE_type passed to "
                         "ssWriteRTWNameValuePair");
        ans = 0;
        goto EXIT_POINT;
    }

    if (name == NULL || name[0] == '\0') {
        ssSetErrorStatus(S, "Invalid name passed to "
                            "ssWriteRTWNameValuePair");
        ans = 0;
        goto EXIT_POINT;
    }

    if (nRows < 0 || nCols < 0 ||
        (haveNCols && ((nRows==0 && nCols!=0) || (nRows!=0 && nCols==0)))) {
        ssSetErrorStatus(S, "Invalid number of rows or columns passed to "
                         "ssWriteRTWNameValuePair");
        ans = 0;
        goto EXIT_POINT;
    }
            
    if (nRows != 0) {
        int_T ok = 1; 

        if (haveImData) {
            const void **v2 = (const void **)value;
            if (v2[0] == NULL ||
                (GET_COMPLEX_SIGNAL(dtInfo) && v2[1] == NULL)) {
                ok = 0;
            }
        } else if (value == NULL) {
            ok = 0;
        }

        if (!ok) {
            ssSetErrorStatus(S, "Invalid value (NULL) passed to "
                             "ssWriteRTWNameValuePair");
            ans = 0;
            goto EXIT_POINT;
        }
    }


#   if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#   pragma mpwc on
#   endif
    ans = (*S->mdlInfo->writeRTWNameValuePairFcn)(S->mdlInfo->writeRTWFcnArg,
                                        type, name, pValue,  dtInfo, nRows, nCols);
#   if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#   pragma mpwc off
#   endif

EXIT_POINT:

    va_end(ap);
    return(ans);

} /* end ssWriteRTWNameValuePair */



/* Function: ssWriteRTWParameters =============================================
 * Abstract:
 *	Used in mdlRTW to create Parameter records for your S-function.
 *      nParams is the number of tunable S-function parameters. Each parameter
 *	starts with an SSWRITE_VALUE_type which can be:
 *
 *         SSWRITE_VALUE_VECT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const real_T   *valueVect,
 *           int_T          vectLen
 *
 *         SSWRITE_VALUE_2DMAT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const real_T   *valueMat,
 *           int_T          nRows,
 *           int_T          nCols
 *
 *         SSWRITE_VALUE_DTYPE_VECT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const void     *valueVect,
 *           int_T          vectLen,
 *           int_T          dtInfo
 *
 *         SSWRITE_VALUE_DTYPE_2DMAT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const void     *valueMat,
 *           int_T          nRows,
 *           int_T          nCols,
 *           int_T          dtInfo
 *
 *         SSWRITE_VALUE_DTYPE_ML_VECT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const void     *rValueVect,
 *           const void     *iValueVect,
 *           int_T          vectLen,
 *           int_T          dtInfo
 *
 *         SSWRITE_VALUE_DTYPE_ML_2DMAT,
 *           const char_T   *paramName,
 *           const char_T   *stringInfo,
 *           const void     *rValueMat,
 *           const void     *iValueMat,
 *           int_T          nRows,
 *           int_T          nCols,
 *           int_T          dtInfo
 *	
 */
int_T ssWriteRTWParameters(SimStruct *S, int_T nParams, ...)
{
    int_T     i;
    int_T     ans = 1; /* assume */
    va_list   ap;
    va_start(ap, nParams);

    for (i=0; i< nParams; i++) {
        int_T        type   = va_arg(ap, int_T);
        const char_T *name  = va_arg(ap, const char_T *);
        const char_T *str   = va_arg(ap, const char_T *);
        int_T        dtInfo = 0; /* real and double */
        int_T        nRows;
        int_T        nCols;
        const void   *ppValue[2];
        const void   *pValue;


        switch (type) {
          case SSWRITE_VALUE_VECT:
            {
                pValue = va_arg(ap, const real_T *);
                nRows  = va_arg(ap, int_T);
                nCols  = (nRows == 0)? 0: 1;
                dtInfo = 0; /* real, double */
            }
            break;
          case SSWRITE_VALUE_2DMAT:
            {
                pValue = va_arg(ap, const real_T *);
                nRows  = va_arg(ap, int_T);
                nCols  = va_arg(ap, int_T);
                dtInfo = 0; /* real, double */
            }
            break;
          case SSWRITE_VALUE_DTYPE_VECT:
            {
                pValue = va_arg(ap, const void *);
                nRows  = va_arg(ap, int_T);
                nCols  = (nRows == 0)? 0: 1;
                dtInfo = va_arg(ap, int_T);
            }
            break;
          case SSWRITE_VALUE_DTYPE_2DMAT:
            {
                pValue = va_arg(ap, const void *);
                nRows  = va_arg(ap, int_T);
                nCols  = va_arg(ap, int_T);
                dtInfo = va_arg(ap, int_T);
            }
            break;
          case SSWRITE_VALUE_DTYPE_ML_VECT:
            {
                ppValue[0] = va_arg(ap, const void *); /* real part */
                ppValue[1] = va_arg(ap, const void *); /* imag part */
                pValue     = ppValue;

                nRows      = va_arg(ap, int_T);
                nCols      = (nRows == 0)? 0: 1;
                dtInfo     = va_arg(ap, int_T);
            }
            break;
          case SSWRITE_VALUE_DTYPE_ML_2DMAT:
            {
                ppValue[0] = va_arg(ap, const void *);
                ppValue[1] = va_arg(ap, const void *); 
                pValue     = ppValue;

                nRows      = va_arg(ap, int_T);
                nCols      = va_arg(ap, int_T);
                dtInfo     = va_arg(ap, int_T);
            }
            break;
          default:
            ssSetErrorStatus(S, "Invalid SSWRITE_VALUE_type passed to "
                             "ssWriteRTWParameters");
            ans = 0;
            goto EXIT_POINT;
        }

        if ( name == NULL || name[0] == '\0' ||
             (pValue == NULL && nRows != 0) || 
             nRows < 0 || nCols < 0 ||
             (nRows == 0 && nCols != 0) || (nRows != 0 && nCols == 0)) {
             ssSetErrorStatus(S, "Invalid arguments passed to "
                              "ssWriteRTWParameters");
            ans = 0;
            goto EXIT_POINT;
        }
            
#       if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#       pragma mpwc on
#       endif
        ans = (*S->mdlInfo->writeRTWParameterFcn)(S->mdlInfo->writeRTWFcnArg,
                                                  type, name, str, pValue, 
                                                  dtInfo, nRows, nCols);
#       if SS_DO_FCN_CALL_ON_MAC && defined(__MWERKS__)
#       pragma mpwc off
#       endif

        if (ans == 0) {
            goto EXIT_POINT;
        }
    }

  EXIT_POINT:

    va_end(ap);
    return(ans);

} /* end ssWriteRTWParameters */



/* Function: ssWriteRTWParamSettings ==========================================
 * Abstract:
 *	Used in mdlRTW to create the SFcnParameterSettings record for
 *	your S-function (these are generally derived from the non-tunable
 *	parameters). For each parameter a "group" of values must be specified.
 *	These adhear to the the following format:
 *
 *         SSWRITE_VALUE_STR,              - Used to write (un)quoted strings
 *           const char_T *settingName,      example:
 *           const char_T *value,              Country      USA
 *
 *         SSWRITE_VALUE_QSTR,             - Used to write quoted strings
 *           const char_T *settingName,      example:
 *           const char_T *value,              Country      "U.S.A"
 *
 *         SSWRITE_VALUE_VECT_STR,         - Used to write vector of strings
 *           const char_T *settingName,      example:
 *           const char_T *value,              Countries    ["USA", "Mexico"]
 *           int_T        nItemsInVect
 *
 *         SSWRITE_VALUE_NUM,              - Used to write numbers
 *           const char_T *settingName,      example:
 *           const real_T value                 NumCountries  2
 *
 *
 *         SSWRITE_VALUE_VECT,             - Used to write numeric vectors
 *           const char_T *settingName,      example:
 *           const real_T *settingValue,       PopInMil        [300, 100]
 *           int_T        vectLen
 *
 *         SSWRITE_VALUE_2DMAT,            - Used to write 2D matrices
 *           const char_T *settingName,      example:
 *           const real_T *settingValue,       PopInMilBySex  Matrix(2,2)
 *           int_T        nRows,                   [[170, 130],[60, 40]]
 *           int_T        nCols
 *
 *         SSWRITE_VALUE_DTYPE_NUM,        - Used to write numeric vectors
 *           const char_T   *settingName,    example: int8 Num 3+4i
 *           const void     *settingValue,   written as: [3+4i]
 *           int_T          dtInfo
 *
 *
 *         SSWRITE_VALUE_DTYPE_VECT,       - Used to write data typed vectors
 *           const char_T   *settingName,    example: int8 CArray [1+2i 3+4i]
 *           const void     *settingValue,   written as:
 *           int_T          vectLen             CArray  [1+2i, 3+4i]
 *           int_T          dtInfo
 *
 *
 *         SSWRITE_VALUE_DTYPE_2DMAT,      - Used to write data typed 2D
 *           const char_T   *settingName     matrices
 *           const void     *settingValue,   example:
 *           int_T          nRow ,            int8 CMatrix  [1+2i 3+4i; 5 6]
 *           int_T          nCols,            written as:
 *           int_T          dtInfo               CMatrix         Matrix(2,2)
 *                                                [[1+2i, 3+4i]; [5+0i, 6+0i]]
 *
 *
 *         SSWRITE_VALUE_DTYPE_ML_VECT,    - Used to write complex matlab data
 *           const char_T   *settingName,    typed vectors example:
 *           const void     *settingRValue,  example: int8 CArray [1+2i 3+4i]
 *           const void     *settingIValue,      settingRValue: [1 3]
 *           int_T          vectLen              settingIValue: [2 4]
 *           int_T          dtInfo
 *                                             written as:
 *                                                CArray    [1+2i, 3+4i]
 *
 *         SSWRITE_VALUE_DTYPE_ML_2DMAT,   - Used to write matlab complex
 *           const char_T   *settingName,    data typed 2D matrices
 *           const void     *settingRValue,  example
 *           const void     *settingIValue,      int8 CMatrix [1+2i 3+4i; 5 6]
 *           int_T          nRows                settingRValue: [1 5 3 6]
 *           int_T          nCols,               settingIValue: [2 0 4 0]
 *           int_T          dtInfo
 *                                              written as:
 *                                              CMatrix         Matrix(2,2)
 *                                                [[1+2i, 3+4i]; [5+0i, 6+0i]]
 *
 *-----------------------------------------------------------------------------
 */
int_T ssWriteRTWParamSettings(SimStruct *S, int_T nParams, ...)
{
    int_T i;
    int_T ans   = 1; /* assume */

    va_list   ap;
    va_start(ap, nParams);

    if (nParams <= 0) {
        ans = 0;
        goto EXIT_POINT;
    }

    if ( (ans = ssWriteRTWStr(S, "SFcnParamSettings {")) != 1 ) {
        goto EXIT_POINT;
    }
    for (i=0; i< nParams; i++) {
        int_T        type   = va_arg(ap, int_T);
        const char_T *name  = va_arg(ap, const char_T *);
        int_T        dtInfo = 0; /* real and double */
        int_T        nRows;
        int_T        nCols;

        switch (type) {
          case SSWRITE_VALUE_STR:
            /*FALLTHROUGH*/
          case SSWRITE_VALUE_QSTR: {
            const char_T *pValue = va_arg(ap, const char_T *);
            ans = ssWriteRTWNameValuePair(S,type,name,pValue);
            break;
          }
          case SSWRITE_VALUE_VECT_STR: {
            const char_T *pValue = va_arg(ap, const char_T *);
            nRows = va_arg(ap, int_T);
            ans = ssWriteRTWNameValuePair(S,type,name,pValue,nRows);
            break;
          }
          case SSWRITE_VALUE_NUM: {
            real_T value = va_arg(ap, real_T);
            ans = ssWriteRTWNameValuePair(S,type,name,&value,dtInfo);
            break;
          }
          case SSWRITE_VALUE_VECT: {
            const real_T *pValue = va_arg(ap, const real_T *);
            nRows = va_arg(ap, int_T);
            ans = ssWriteRTWNameValuePair(S,type,name,pValue,dtInfo,nRows);
            break;
          }
          case SSWRITE_VALUE_2DMAT: {
            const real_T *pValue = va_arg(ap, const real_T *);
            nRows = va_arg(ap, int_T);
            nCols = va_arg(ap, int_T);
            ans= ssWriteRTWNameValuePair(S,type,name,pValue,
                                         dtInfo,nRows,nCols);
            break;
          }
          case SSWRITE_VALUE_DTYPE_NUM: {
            const void *pValue = va_arg(ap, const void *);
            dtInfo = va_arg(ap, int_T);
            ans    = ssWriteRTWNameValuePair(S,type,name,pValue,dtInfo);
            break;
          }
          case SSWRITE_VALUE_DTYPE_VECT: {
            const void *pValue = va_arg(ap, const void *);
            nRows  = va_arg(ap, int_T);
            dtInfo = va_arg(ap, int_T);
            ans    = ssWriteRTWNameValuePair(S,type,name,pValue,dtInfo,nRows);
            break;
          }
          case SSWRITE_VALUE_DTYPE_2DMAT: {
            const void *pValue = va_arg(ap, const void *);
            nRows  = va_arg(ap, int_T);
            nCols  = va_arg(ap, int_T);
            dtInfo = va_arg(ap, int_T);
            ans    = ssWriteRTWNameValuePair(S,type,name,pValue,
                                             dtInfo,nRows,nCols);
            break;
          }
          case SSWRITE_VALUE_DTYPE_ML_VECT: {
            const void *pValue[2];
            pValue[0] = va_arg(ap, const void *);
            pValue[1] = va_arg(ap, const void *);
            nRows  = va_arg(ap, int_T);
            dtInfo = va_arg(ap, int_T);
            ans    = ssWriteRTWNameValuePair(S,type,name,pValue,dtInfo,nRows);
            break;
          }
          case SSWRITE_VALUE_DTYPE_ML_2DMAT: {
            const void *pValue[2];
            pValue[0] = va_arg(ap, const void *);
            pValue[1] = va_arg(ap, const void *);
            nRows  = va_arg(ap, int_T);
            nCols  = va_arg(ap, int_T);
            dtInfo = va_arg(ap, int_T);
            ans    = ssWriteRTWNameValuePair(S,type,name,pValue,
                                             dtInfo,nRows,nCols);
            break;
          }
          default:
            ssSetErrorStatus(S, "Invalid SSWRITE_VALUE_type passed to "
                                "ssWriteRTWParamSettings");
            ans = 0;
            goto EXIT_POINT;
        }
        if (ans != 1) {
            goto EXIT_POINT;
        }
    }
    if ( (ans = ssWriteRTWStr(S, "}")) != 1 ) {
        goto EXIT_POINT;
    }

  EXIT_POINT:

    va_end(ap);
    return(ans);

} /* end ssWriteRTWParamSettings */



/* Function: ssWriteRTWWorkVect ===============================================
 * Abstract:
 *    Used in mdlRTW to create work vector records for S-functions:
 *
 *       if (!ssWriteRTWWorkVect(S, vectName, nNames,
 *
 *                            name, size,   (must have nNames of these pairs)
 *                                 :
 *                           ) ) {
 *           return;  (error reporting will be handled by SL)
 *       }
 *
 *       Notes:
 *         a) vectName must be either "RWork", "IWork" or "PWork"
 *         b) nNames is an int_T, name is a const char_T* and size is int_T, and
 *            there must be nNames number of [name, size] pairs passed to the
 *            function.
 *         b) intSize1+intSize2+ ... +intSizeN = ssGetNum<vectName>(S)
 *            Recall that you would have to set ssSetNum<vectName>(S)
 *            in one of the initialization functions (mdlInitializeSizes
 *            or mdlSetWorkVectorWidths).
 *	
 */
int_T ssWriteRTWWorkVect(SimStruct    *S,
                         const char_T *vectName,
                         int_T        nNames,
                         ...)
{
    int_T     i;
    int_T     nElementsWritten  = 0;
    int_T     nElementsExpected = 0;
    int_T     ans               = 1; /* assume */
    char_T    strBuf[40]        = "\0";
    va_list   ap;
    va_start(ap, nNames);

    /* vectName must be RWork, IWork or PWork */
    if ( (strcmp(vectName,"RWork") != 0 &&
          strcmp(vectName,"IWork") != 0 &&
          strcmp(vectName,"PWork") != 0) ||
         (strlen(vectName) + sizeof("NumDefines") > sizeof(strBuf))) {
        ssSetErrorStatus(S, "Invalid work vector name (vectName) passed to "
                         "ssWriteRTWWorkVect (must be RWork, IWork, or PWork");
        ans = 0;
        goto EXIT_POINT;
    }

    if (nNames <= 0) {
        ssSetErrorStatus(S, "nNames argument to ssWriteRTWWorkVect must be "
                         "greater than 0");
        ans = 0;
        goto EXIT_POINT;
    }


    if (strcmp(vectName, "RWork") == 0) {
        nElementsExpected = ssGetNumRWork(S);
    } else if (strcmp(vectName, "IWork") == 0) {
        nElementsExpected = ssGetNumIWork(S);
    }  else if (strcmp(vectName, "PWork") == 0) {
        nElementsExpected = ssGetNumPWork(S);
    } else {
        ssSetErrorStatus(S, "Invalid arguments passed to ssWriteRTWWorkVect");
        ans = 0;
        goto EXIT_POINT;
    }
        

    (void)sprintf(strBuf,"Num%sDefines",vectName);
    ans = ssWriteRTWNameValuePair(S,SSWRITE_VALUE_DTYPE_NUM,strBuf,
                                  &nNames, DTINFO(SS_INT32, 0));
    if (ans != 1) goto EXIT_POINT;
        
    for (i = 0; i < nNames; i++) {
        const char_T *name = va_arg(ap, const char_T *);
        int_T        width = va_arg(ap, int_T);

        (void)sprintf(strBuf, "%sDefine {",vectName);
        ans = ssWriteRTWStr(S,strBuf);
        if (ans != 1) goto EXIT_POINT;

        ans = ssWriteRTWNameValuePair(S,SSWRITE_VALUE_QSTR,"Name",name);
        if (ans != 1) goto EXIT_POINT;

        ans = ssWriteRTWNameValuePair(S,SSWRITE_VALUE_DTYPE_NUM,"Width",
                                      &width, DTINFO(SS_INT32, 0));
        if (ans != 1) goto EXIT_POINT;

        ans = ssWriteRTWNameValuePair(S,SSWRITE_VALUE_DTYPE_NUM,"StartIndex",
                                      &nElementsWritten, DTINFO(SS_INT32,0));
        if (ans != 1) goto EXIT_POINT;

        ans = ssWriteRTWStr(S, "}");
        if (ans != 1) goto EXIT_POINT;

        nElementsWritten += width;
    }

    if (nElementsWritten != nElementsExpected) {
        static char_T errmsg[200];
        (void)sprintf(errmsg,
                      "Error in ssWriteRTWWorkVect.  The total number of "
                      "%sDefines written to the .rtw file (= %d), should be "
                      "equal to number of %s (= %d), registered in "
                      "mdlInitializeSizes",
                      vectName, nElementsWritten,
                      vectName, nElementsExpected);
        ssSetErrorStatus(S, errmsg);
        ans = 0;
    }

  EXIT_POINT:
    va_end(ap);
    return(ans);

} /* end ssWriteRTWWorkVect */



/*===================================*
 * Fix for MrC optimization problems *
 *===================================*/

/*
 * MAC - Require local stack frames for routines placed in the function
 * pointer table to work around bugs in MrC compiler.
 */

#if defined(__MRC__)

#define REQUIRE_LOCAL_STACK_FRAME volatile int_T __requireLocalStackFrame = 0

static void __mdlInitializeSizes(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlInitializeSizes(S);
}

#if S_FUNCTION_LEVEL == 1
# if defined(MDL_GET_INPUT_PORT_WIDTH)
    static int_T __mdlGetInputPortWidth(SimStruct *S, int_T outputWidth)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        return mdlGetInputPortWidth(S, outputWidth);
    }
#  endif

# if defined(MDL_GET_OUTPUT_PORT_WIDTH)
    static int_T __mdlGetOutputPortWidth(SimStruct *S, int_T inputWidth)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        return mdlGetOutputPortWidth(S, inputWidth);
    }
# endif
#endif


#if S_FUNCTION_LEVEL == 2

# if defined(MDL_SET_INPUT_PORT_WIDTH)
    static void __mdlSetInputPortWidth(SimStruct *S, int_T port, int_T width)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetInputPortWidth(S, port, width);
    }
# endif

# if defined(MDL_SET_OUTPUT_PORT_WIDTH)
    static void __mdlSetOutputPortWidth(SimStruct *S, int_T port, int_T width)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetOutputPortWidth(S, port, width);
    }
# endif

# if defined(MDL_SET_INPUT_PORT_DIMENSION_INFO)
    static void __mdlSetInputPortDimensionInfo(SimStruct        *S, 
                                               int_T            port, 
                                               const DimsInfo_T *dimsInfo)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetInputPortDimensionInfo(S, port, dimsInfo);
    }
# endif

# if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO)
    static void __mdlSetOutputPortDimensionInfo(SimStruct        *S, 
                                                int_T            port, 
                                                const DimsInfo_T *dimsInfo)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetOutputPortDimensionInfo(S, port, dimsInfo);
    }
# endif

# if defined(MDL_SET_DEFAULT_PORT_DIMENSION_INFO)
    static void __mdlSetDefaultPortDimensionInfo(SimStruct *S)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetDefaultPortDimensionInfo(S);
    }
# endif

# if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME)
    static void __mdlSetInputPortSampleTime(SimStruct *S, int_T port, 
                                            real_T sampleTime, 
                                            real_T offsetTime)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetInputPortSampleTime(S, port, sampleTime, offsetTime);
    }
# endif

# if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME)
    static void __mdlSetOutputPortSampleTime(SimStruct *S, int_T port, 
                                             real_T sampleTime,
                                             real_T offsetTime)
    {
        REQUIRE_LOCAL_STACK_FRAME;
        mdlSetOutputPortSampleTime(S, port, sampleTime, offsetTime);
    }
# endif

#   if defined(MDL_SET_INPUT_PORT_DATA_TYPE)
      static void __mdlSetInputPortDataType(SimStruct *S, int_T port,
                                            DTypeId   inputPortDataType)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetInputPortDataType(S, port, inputPortDataType);
      }
#   endif
  
#   if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE)
      static void __mdlSetOutputPortDataType(SimStruct *S, int_T port,
                                             DTypeId   outputPortDataType)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetOutputPortDataType(S, port, outputPortDataType);
      }
#   endif

#   if defined(MDL_SET_DEFAULT_PORT_DATA_TYPES)
      static void __mdlSetDefaultPortDataTypes(SimStruct *S)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetDefaultPortDataTypes(S);
      }
#   endif



#   if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL)
      static void __mdlSetInputPortComplexSignal(SimStruct *S, int_T port,
                                                 int_T iPortComplexSignal)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetInputPortComplexSignal(S, port, iPortComplexSignal);
      }
#   endif
  
#   if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL)
      static void __mdlSetOutputPortComplexSignal(SimStruct *S, int_T port,
                                                 int_T oPortComplexSignal)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetOutputPortComplexSignal(S, port, oPortComplexSignal);
      }
#   endif

#   if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS)
      static void __mdlSetDefaultPortComplexSignals(SimStruct *S)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetDefaultPortComplexSignals(S);
      }
#   endif


#   if defined(MDL_SET_INPUT_PORT_FRAME_DATA)
      static void __mdlSetInputPortFrameData(SimStruct *S, int_T port,
                                            Frame_T   iPortFrameData)
      {
          REQUIRE_LOCAL_STACK_FRAME;
          mdlSetInputPortFrameData(S, port, iPortFrameData);
      }
#   endif
  
#endif

static void __mdlInitializeSampleTimes(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlInitializeSampleTimes(S);
}

#if defined(MDL_SET_WORK_WIDTHS)
static void __mdlSetWorkWidths(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlSetWorkWidths(S);
}
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_RTW)
  static void __mdlRTW(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlRTW(S);
  }
#endif



#if S_FUNCTION_LEVEL == 1
  static void __mdlInitializeConditions(real_T *x0, SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlInitializeConditions(x0, S);
  }
#elif defined(MDL_INITIALIZE_CONDITIONS)
  static void __mdlInitializeConditions(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlInitializeConditions(S);
  }
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_START)
  static void __mdlStart(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlStart(S);
  }
#endif

#if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_ENABLE)
  static void __mdlEnable(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlEnable(S);
  }
#endif

#if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_DISABLE)
  static void __mdlDisable(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlDisable(S);
  }
#endif

#if defined(MDL_CHECK_PARAMETERS)
  static void __mdlCheckParameters(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlCheckParameters(S);
  }
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_PROCESS_PARAMETERS)
  static void __mdlProcessParameters(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlProcessParameters(S);
  }
#endif

static void __mdlGetTimeOfNextVarHit(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlGetTimeOfNextVarHit(S);
}

#if S_FUNCTION_LEVEL == 1
  static void __mdlOutputs(real_T *y, real_T *x, real_T *u, SimStruct *S,
                           int_T tid)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlOutputs(y, x, u, S, tid);
  }
#else
  static void __mdlOutputs(SimStruct *S, int_T tid)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlOutputs(S, tid);
  }
#endif

#if S_FUNCTION_LEVEL == 1
  static void __mdlUpdate(real_T *x, real_T *u, SimStruct *S, int_T tid)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlUpdate(x, u, S, tid);
  }
#elif defined(MDL_UPDATE)
  static void __mdlUpdate(SimStruct *S, int_T tid)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlUpdate(S, tid);
  }
#endif

#if S_FUNCTION_LEVEL == 1
  static void __mdlDerivatives(real_T *dx, real_T *x, real_T *u, SimStruct *S,
                               int_T tid)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlDerivatives(dx, x, u, S, tid);
  }
#elif defined(MDL_DERIVATIVES)
  static void __mdlDerivatives(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlDerivatives(S);
  }
#endif

#if defined(MDL_JACOBIAN)
  static void __mdlJacobian(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlJacobian(S);
  }
#endif

#if defined(MDL_PROJECTION)
  static void __mdlProjection(SimStruct *S)
  {
      REQUIRE_LOCAL_STACK_FRAME;
      mdlProjection(S);
  }
#endif

static void __mdlZeroCrossings(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlZeroCrossings(S);
}

static void __mdlTerminate(SimStruct *S)
{
    REQUIRE_LOCAL_STACK_FRAME;
    mdlTerminate(S);
}

#else

#if !defined(ADA_S_FUNCTION)
/* Ada S-Function's mdlInitializeSizes is called from __mdlInitializeSizes */
# define __mdlInitializeSizes          mdlInitializeSizes
#endif

#if S_FUNCTION_LEVEL == 1

# if defined(MDL_GET_INPUT_PORT_WIDTH)
#  define __mdlGetInputPortWidth      mdlGetInputPortWidth
# endif

# if defined(MDL_GET_OUTPUT_PORT_WIDTH)
#  define __mdlGetOutputPortWidth     mdlGetOutputPortWidth
# endif

#else /* level 2 */

# if defined(MDL_SET_INPUT_PORT_WIDTH)
#  define __mdlSetInputPortWidth      mdlSetInputPortWidth
# endif

# if defined(MDL_SET_OUTPUT_PORT_WIDTH)
#  define __mdlSetOutputPortWidth     mdlSetOutputPortWidth
# endif

# if defined(MDL_SET_INPUT_PORT_DIMENSION_INFO)
#  define __mdlSetInputPortDimensionInfo      mdlSetInputPortDimensionInfo
# endif

# if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO)
#  define __mdlSetOutputPortDimensionInfo     mdlSetOutputPortDimensionInfo
# endif

# if defined(MDL_SET_DEFAULT_PORT_DIMENSION_INFO)
#  define __mdlSetDefaultPortDimensionInfo     mdlSetDefaultPortDimensionInfo
# endif

# if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME)
#  define __mdlSetInputPortSampleTime   mdlSetInputPortSampleTime
# endif

# if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME)
#  define __mdlSetOutputPortSampleTime  mdlSetOutputPortSampleTime
# endif



# if defined(MDL_SET_INPUT_PORT_DATA_TYPE)
#  define __mdlSetInputPortDataType   mdlSetInputPortDataType
# endif

# if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE)
#  define __mdlSetOutputPortDataType  mdlSetOutputPortDataType
# endif

# if defined(MDL_SET_DEFAULT_PORT_DATA_TYPES)
#  define __mdlSetDefaultPortDataTypes  mdlSetDefaultPortDataTypes
# endif


# if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL)
#  define __mdlSetInputPortComplexSignal   mdlSetInputPortComplexSignal
# endif

# if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL)
#  define __mdlSetOutputPortComplexSignal  mdlSetOutputPortComplexSignal
# endif

# if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS)
#  define __mdlSetDefaultPortComplexSignals  mdlSetDefaultPortComplexSignals
# endif


# if defined(MDL_SET_INPUT_PORT_FRAME_DATA)
#  define __mdlSetInputPortFrameData   mdlSetInputPortFrameData
# endif

#endif

#define __mdlInitializeSampleTimes    mdlInitializeSampleTimes

#if !defined(ADA_S_FUNCTION)
/* Ada S-Function's mdlSetWorkWidths is called from __mdlSetWorkWidths */
#define __mdlSetWorkWidths            mdlSetWorkWidths
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_RTW)
# define __mdlRTW                     mdlRTW
#endif

#if S_FUNCTION_LEVEL == 1 || defined(MDL_INITIALIZE_CONDITIONS)
# define __mdlInitializeConditions    mdlInitializeConditions
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_START)
# define __mdlStart                   mdlStart
#endif

#if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_ENABLE)
# define __mdlEnable                  mdlEnable
#endif

#if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_DISABLE)
# define __mdlDisable                  mdlDisable
#endif

#if defined(MDL_CHECK_PARAMETERS)
# define __mdlCheckParameters         mdlCheckParameters
#endif

#if S_FUNCTION_LEVEL == 2 && defined(MDL_PROCESS_PARAMETERS)
# define __mdlProcessParameters       mdlProcessParameters
#endif

#define __mdlGetTimeOfNextVarHit      mdlGetTimeOfNextVarHit

#define __mdlOutputs                  mdlOutputs

#if S_FUNCTION_LEVEL == 1 || defined(MDL_UPDATE)
# define __mdlUpdate                  mdlUpdate
#endif

#if S_FUNCTION_LEVEL == 1 || defined(MDL_DERIVATIVES)
# define __mdlDerivatives             mdlDerivatives
#endif

#if defined(MDL_JACOBIAN)
# define __mdlJacobian                mdlJacobian
#endif

#if defined(MDL_PROJECTION)
# define __mdlProjection              mdlProjection
#endif

#define __mdlZeroCrossings            mdlZeroCrossings

#if !defined(ADA_S_FUNCTION)
/* Ada S-Function's mdlTerminate is called from __mdlTerminate */
#define __mdlTerminate                mdlTerminate
#endif

#endif /* defined __MRC__ */



/* Function: _ProcessMexSfunctionCmdLineCall ==================================
 * Abstract:
 *      Process a MEX S-function call which was issued at the MATLAB
 *      command line.
 *
 *      The only vaild command is the sizes initialization:
 *
 *      [sizes,x0,str,ts,xts]=sfunc([],[],[],0)
 *
 *      Thrid parameter U is required if we have dynamically sized
 *      vector(s).
 */
#ifdef V4_COMPAT
static void _ProcessMexSfunctionCmdLineCall
(
 int_T       nlhs,
 Matrix      *plhs[],
 int_T       nrhs,
 Matrix      *prhs[]
)
#else
static void _ProcessMexSfunctionCmdLineCall
(
 int_T         nlhs,
 mxArray       *plhs[],
 int_T         nrhs,
 const mxArray *prhs[]
)
#endif /* V4_COMPAT */
{
    char_T    errmsg[256];
#   if defined(ADA_S_FUNCTION)
    int_T     tempSimStruct = 0; /* assume */
#   endif
    SimStruct *S;
    int_T     flag;
    real_T    flagDbl;
    real_T    *dptr;

    /************************************************
     * Verify arguments aren't outside their limits *
     ************************************************/

    if (nrhs < 4) {
        (void)sprintf(errmsg,
                "%s must be be called with at least 4 right hand arguments",
                _sfcnName);
        mexErrMsgTxt(errmsg);
    }

    if (nlhs > 1) {
        (void)sprintf(errmsg,
                "%s called with too many left hand arguments",
                _sfcnName);
        mexErrMsgTxt(errmsg);
    }


    /*******************************
     * Get flag and verify it is 0 *
     *******************************/

    if (_GetNumEl(prhs[_RHS_FLAG]) != 1 ||
        mxIsComplex(prhs[_RHS_FLAG]) || !mxIsNumeric(prhs[_RHS_FLAG])) {
        (void)sprintf(errmsg, "The 4th right hand argument, FLAG, "
                      "passed to %s must be an integer",_sfcnName);
        mexErrMsgTxt(errmsg);
    }

    flagDbl = *(real_T*)mxGetPr(prhs[_RHS_FLAG]);
    flag = (int_T) flagDbl;

    if ((real_T)flag != flagDbl) {
        (void)sprintf(errmsg, "The 4th right hand argument, FLAG, "
                      "passed to %s must be an integer",_sfcnName);
        mexErrMsgTxt(errmsg);
    }

    if (flag != 0) {
        (void)sprintf(errmsg,"Invalid flag passed to %s", _sfcnName);
        mexErrMsgTxt(errmsg);
    }



    /*******************************************
     * Get SimStruct or create a temporary one *
     *******************************************/
    {
        int_T    m   = mxGetM(prhs[_RHS_X]);
        real_T   *pr = ((m == sizeof(SimStruct *)/sizeof(int_T) + 1)?
                      (real_T*)mxGetPr(prhs[_RHS_X]): (real_T*)NULL);
        /*
         * If number of rows is equal to a pointer split across int_T's,
         * then the SimStruct pointer is incodede in the X argument.
         * The pointer comes first. The version of the passed SimStruct comes
         * second.
         */
        if (pr != NULL && pr[m-1] == SIMSTRUCT_VERSION_LEVEL2) {
            int_T    *intS = (int_T *)&S;
            int_T    i;

            for (i = 0; i < m - 1; i++) {
                intS[i] = (int_T)pr[i];
            }

            /*
             * Verify that S_FUNCTION_NAME and name entered in the
             * S-function dialog box match
             */
#           if S_FUNCTION_LEVEL == 2
            {
#           else
            if (ssGetSimMode(S) == SS_SIMMODE_RTWGEN) {
#           endif
                const char_T *sfcnName = _QUOTE(S_FUNCTION_NAME);

                if (strcmp(sfcnName,"simulink_only_sfcn") != 0 &&
                    strcmp(ssGetModelName(S),sfcnName) != 0) {
                    (void)sprintf(errmsg, "S-function name mismatch. Name in "
                            "source is \"#define S_FUNCTION_NAME %s\", "
                            "whereas name of the S-function MEX file "
                            "is \"%s\". The source needs to be updated",
                            sfcnName, ssGetModelName(S));
                    mexErrMsgTxt(errmsg);
                }
            }

            /* Since this is Simulink calling us, load function pointers. */

            ssSetmdlInitializeSizes(S,__mdlInitializeSizes);

#           if S_FUNCTION_LEVEL==1 && defined(MDL_GET_INPUT_PORT_WIDTH)
                ssSetmdlGetInputPortWidthLevel1(S,
                    (mdlGetInputPortWidthLevel1Fcn)__mdlGetInputPortWidth);
#           endif

#           if S_FUNCTION_LEVEL==1 && defined(MDL_GET_OUTPUT_PORT_WIDTH)
                ssSetmdlGetOutputPortWidthLevel1(S,
                    (mdlGetOutputPortWidthLevel1Fcn)__mdlGetOutputPortWidth);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_INPUT_PORT_WIDTH)
                ssSetmdlSetInputPortWidth(S,__mdlSetInputPortWidth);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_OUTPUT_PORT_WIDTH)
                ssSetmdlSetOutputPortWidth(S,__mdlSetOutputPortWidth);
#           endif

                
#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_INPUT_PORT_DIMENSION_INFO)
             ssSetmdlSetInputPortDimensions(S,__mdlSetInputPortDimensionInfo);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO)
             ssSetmdlSetOutputPortDimensions(S,__mdlSetOutputPortDimensionInfo);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_DEFAULT_PORT_DIMENSION_INFO)
             ssSetmdlSetDefaultPortDimensions(S,__mdlSetDefaultPortDimensionInfo);
#           endif


#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_INPUT_PORT_SAMPLE_TIME)
                ssSetmdlSetInputPortSampleTime(S,__mdlSetInputPortSampleTime);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME)
                ssSetmdlSetOutputPortSampleTime(S,__mdlSetOutputPortSampleTime);
#           endif

#           if  S_FUNCTION_LEVEL==2 
#             if defined(MDL_SET_INPUT_PORT_DATA_TYPE)
                  ssSetmdlSetInputPortDataType(S,__mdlSetInputPortDataType);
#             endif

#             if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE)
                  ssSetmdlSetOutputPortDataType(S,__mdlSetOutputPortDataType);
#             endif

#             if defined(MDL_SET_DEFAULT_PORT_DATA_TYPES)
                  ssSetmdlSetDefaultPortDataTypes(S,__mdlSetDefaultPortDataTypes);
#             endif


#             if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL)
                  ssSetmdlSetInputPortComplexSignal(S,
                                              __mdlSetInputPortComplexSignal);
#             endif

#             if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL)
                  ssSetmdlSetOutputPortComplexSignal(S,
                                              __mdlSetOutputPortComplexSignal);
#             endif

#             if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS)
                  ssSetmdlSetDefaultPortComplexSignals(S,
                                              __mdlSetDefaultPortComplexSignals);
#             endif


#             if defined(MDL_SET_INPUT_PORT_FRAME_DATA)
                  ssSetmdlSetInputPortFrameData(S,__mdlSetInputPortFrameData);
#             endif

#           endif

#           if defined(MDL_SET_WORK_WIDTHS)
                ssSetmdlSetWorkWidths(S,__mdlSetWorkWidths);
#           endif
#           if S_FUNCTION_LEVEL==2 && defined(MDL_RTW)
                ssSetmdlRTW(S,__mdlRTW);
#           endif

            ssSetmdlInitializeSampleTimes(S,__mdlInitializeSampleTimes);

#           if S_FUNCTION_LEVEL==1
              ssSetmdlInitializeConditionsLevel1(S,
                (mdlInitializeConditionsLevel1Fcn)__mdlInitializeConditions);
#           elif defined(MDL_INITIALIZE_CONDITIONS)
              ssSetmdlInitializeConditions(S,__mdlInitializeConditions);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_START)
              ssSetmdlStart(S,__mdlStart);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(RTW_GENERATED_ENABLE)
              ssSetRTWGeneratedEnable(S,__mdlEnable);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(RTW_GENERATED_DISABLE)
              ssSetRTWGeneratedDisable(S,__mdlDisable);
#           endif

#           if defined(MDL_CHECK_PARAMETERS)
                ssSetmdlCheckParameters(S,__mdlCheckParameters);
#           endif

#           if S_FUNCTION_LEVEL==2 && defined(MDL_PROCESS_PARAMETERS)
                ssSetmdlProcessParameters(S,__mdlProcessParameters);
#           endif

            ssSetmdlGetTimeOfNextVarHit(S, __mdlGetTimeOfNextVarHit);

#           if S_FUNCTION_LEVEL==1
              ssSetmdlOutputsLevel1(S,(mdlOutputsLevel1Fcn)__mdlOutputs);
#           else
              ssSetmdlOutputs(S,__mdlOutputs);
#           endif

#           if S_FUNCTION_LEVEL==1
              ssSetmdlUpdateLevel1(S,(mdlUpdateLevel1Fcn)__mdlUpdate);
#           elif defined(MDL_UPDATE)
              ssSetmdlUpdate(S,__mdlUpdate);
#           endif

#           if S_FUNCTION_LEVEL==1
            ssSetmdlDerivativesLevel1(S,
              (mdlDerivativesLevel1Fcn)__mdlDerivatives);
#           elif defined(MDL_DERIVATIVES)
            ssSetmdlDerivatives(S,__mdlDerivatives);
#           endif

#           if defined(MDL_JACOBIAN)
              ssSetmdlJacobian(S,__mdlJacobian);
#           endif

#           if defined(MDL_PROJECTION)
              ssSetmdlProjection(S,__mdlProjection);
#           endif

            ssSetmdlZeroCrossings(S, __mdlZeroCrossings);
            ssSetmdlTerminate(S,__mdlTerminate);

        } else {

#           if defined(ADA_S_FUNCTION)
            tempSimStruct = 1;
#           endif
            S = _CreateSimStruct(nrhs,prhs);
        }
    }

#   if S_FUNCTION_LEVEL == 1
       ssSetVersion(S, SIMSTRUCT_VERSION_LEVEL1);
#   else
       ssSetVersion(S, SIMSTRUCT_VERSION_LEVEL2);
#   endif

    /************************
     * Issue the sizes call *
     ************************/

    __mdlInitializeSizes(S);


    /***********************
     * return sizes vector *
     ***********************/
    {
#       define SETU(sizefield) \
        i = (int_T)((uint_T)((&sizefield(S) - (uint_T*)ssGetSizesPtr(S)))); \
        dptr[i] = (real_T)sizefield(S)

        int_T i;
        plhs[_LHS_RET] = mxCreateDoubleMatrix(SIZES_LENGTH, 1, mxREAL);
        dptr = (real_T*) mxGetPr(plhs[_LHS_RET]);
        for (i=0; i<(int_T)SIZES_LENGTH; i++) {
            dptr[i] = (real_T)ssGetSizesPtr(S)[i];
        }

        ssSetOptions(S, (SS_OPTION_SUPPORTS_MULTITASKING |
                         ssGetOptions(S)));

        /* Fix the unsiged items: */
        SETU(ssGetChecksum0);
        SETU(ssGetChecksum1);
        SETU(ssGetChecksum2);
        SETU(ssGetChecksum3);
        SETU(ssGetOptions);
    }

# if defined(ADA_S_FUNCTION)
    /* We need to do additional clean up if this is an Ada S-Function. */
    if ( tempSimStruct == 1 ) {
        __adaSFcnDestroyUserData(S);
    }
# endif

} /* end _ProcessMexSfunctionCmdLineCall */



/* Function: mexFunction ======================================================
 * Abstract:
 *
 *      Simulink C MEX S-function entry point.
 *
 */
#ifdef V4_COMPAT  /* Use MATLAB 4 prototyping for mexFunction */
void mexFunction
(
 int_T    nlhs,               /* in     - number of left hand side arguments  */
 Matrix   *plhs[],            /* in/out - left hand side arguments            */
 int_T    nrhs,               /* in     - number of right hand side arguments */
 Matrix   *prhs[]             /* in     - right hand side arguments           */
)
#else
void mexFunction
(
 int_T   nlhs,               /* in     - number of left hand side arguments  */
 mxArray *plhs[],            /* in/out - left hand side arguments            */
 int_T   nrhs,               /* in     - number of right hand side arguments */
 const mxArray *prhs[]       /* in     - right hand side arguments           */
)
#endif /* V4_COMPAT */
{

    /*
     * We can get called from either Simulink or the MATLAB command line.
     * When called from Simulink, nlhs is negative and the SimStruct is
     * passed in as a left hand side argument.  When called from MATLAB
     * command line, we must create a temporary SimStruct and try our
     * best to perform the requested function specified by the flag
     * parameter.
     */

#ifdef PROCESS_MEX_SFUNCTION_EVERY_CALL
        if(ProcessMexSfunctionEveryCall(nlhs,plhs,nrhs,prhs)) return;
#endif


    if (nlhs < 0) {
        int_T flag = (int_T)(*(real_T*)mxGetPr(prhs[_RHS_FLAG]));

        /*
         * no need for error checking because we are being called from
         * Simulink
         */

        SimStruct *S = (SimStruct *) plhs[_LHS_SS];

        switch(flag) {

#         if S_FUNCTION_LEVEL == 1
          case SS_CALL_MDL_GET_INPUT_PORT_WIDTH:
            if (ssGetmdlGetInputPortWidthLevel1(S) != NULL) {
                int_T outputPortWidth = ssGetMexApiInt1(S);
                int_T uWidth = sfcnGetInputPortWidthLevel1(S, outputPortWidth);
                  ssSetMexApiInt1(S,uWidth);
            } else {
                ssSetErrorStatus(S, "Unexpected call to mdlGetInputPortWidth");
            }
            break;

          case SS_CALL_MDL_GET_OUTPUT_PORT_WIDTH:
            if (ssGetmdlGetOutputPortWidthLevel1(S) != NULL) {
                int_T inputPortWidth = ssGetMexApiInt1(S);
                int_T yWidth = sfcnGetOutputPortWidthLevel1(S, inputPortWidth);
                ssSetMexApiInt1(S,yWidth);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlGetOutputPortWidth");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2
          case SS_CALL_MDL_SET_INPUT_PORT_WIDTH:
            if (ssGetmdlSetInputPortWidth(S) != NULL) {
                int_T port  = ssGetMexApiInt1(S);
                int_T width = ssGetMexApiInt2(S);
                sfcnSetInputPortWidth(S,port,width);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortWidth");
            }
            break;

          case SS_CALL_MDL_SET_OUTPUT_PORT_WIDTH:
            if (ssGetmdlSetOutputPortWidth(S) != NULL) {
                int_T port  = ssGetMexApiInt1(S);
                int_T width = ssGetMexApiInt2(S);
                sfcnSetOutputPortWidth(S,port,width);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetOutputPortWidth");
            }
            break;

          case SS_CALL_MDL_SET_INPUT_PORT_DIMENSION_INFO:
            if (ssGetmdlSetInputPortDimensions(S) != NULL) {
                int_T            port      = ssGetMexApiInt1(S);
                const DimsInfo_T *dimsInfo = (const DimsInfo_T *)
                                              ssGetMexApiVoidPtr1(S);
                sfcnSetInputPortDimensionInfo(S,port,dimsInfo);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortDimensionInfo");
            }
            break;

          case SS_CALL_MDL_SET_OUTPUT_PORT_DIMENSION_INFO:
            if (ssGetmdlSetOutputPortDimensions(S) != NULL) {
                int_T            port      = ssGetMexApiInt1(S);
                const DimsInfo_T *dimsInfo = (const DimsInfo_T *)
                                              ssGetMexApiVoidPtr1(S);
                sfcnSetOutputPortDimensionInfo(S,port,dimsInfo);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetOutputPortDimensionInfo");
            }
            break;

          case SS_CALL_MDL_SET_DEFAULT_PORT_DIMENSION_INFO:
            if (ssGetmdlSetDefaultPortDimensions(S) != NULL) {
                sfcnSetDefaultPortDimensionInfo(S);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetDefaultPortDimensionInfo");
            }
            break;

          case SS_CALL_MDL_SET_INPUT_PORT_SAMPLE_TIME:
            if (ssGetmdlSetInputPortSampleTime(S) != NULL) {
                int_T  port        = ssGetMexApiInt1(S);
                real_T sampleTime  = ssGetMexApiReal1(S);
                real_T offsetTime  = ssGetMexApiReal2(S);
                sfcnSetInputPortSampleTime(S,port,sampleTime,offsetTime);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortSampleTime");
            }
            break;

          case SS_CALL_MDL_SET_OUTPUT_PORT_SAMPLE_TIME:
            if (ssGetmdlSetOutputPortSampleTime(S) != NULL) {
                int_T  port        = ssGetMexApiInt1(S);
                real_T sampleTime  = ssGetMexApiReal1(S);
                real_T offsetTime  = ssGetMexApiReal2(S);
                sfcnSetOutputPortSampleTime(S,port,sampleTime,offsetTime);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetOutputPortSampleTime");
            }
            break;

          case SS_CALL_MDL_SET_INPUT_PORT_DATA_TYPE:
            if (ssGetmdlSetInputPortDataType(S) != NULL) {
                int_T     port               = ssGetMexApiInt1(S);
                DTypeId inputPortDataType  = ssGetMexApiInt2(S);
                sfcnSetInputPortDataType(S,port,inputPortDataType);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortDataType");
            }
            break;

          case SS_CALL_MDL_SET_OUTPUT_PORT_DATA_TYPE:
            if (ssGetmdlSetOutputPortDataType(S) != NULL) {
                int_T     port                = ssGetMexApiInt1(S);
                DTypeId outputPortDataType  = ssGetMexApiInt2(S);
                sfcnSetOutputPortDataType(S,port,outputPortDataType);
            } else {
                ssSetErrorStatus(S,"Unexpected call to "
                                 "mdlSetOutputPortDataType");
            }
            break;

          case SS_CALL_MDL_SET_DEFAULT_PORT_DATA_TYPES:
            if (ssGetmdlSetDefaultPortDataTypes(S) != NULL) {
                sfcnSetDefaultPortDataTypes(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to "
                                 "mdlSetDefaultPortDataTypes");
            }
            break;


          case SS_CALL_MDL_SET_INPUT_PORT_COMPLEX_SIGNAL:
            if (ssGetmdlSetInputPortComplexSignal(S) != NULL) {
                int_T port               = ssGetMexApiInt1(S);
                int_T iPortComplexSignal = (int_T)ssGetMexApiInt2(S);
                sfcnSetInputPortComplexSignal(S,port,iPortComplexSignal);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortComplexSignal");
            }
            break;

          case SS_CALL_MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL:
            if (ssGetmdlSetOutputPortComplexSignal(S) != NULL) {
                int_T port                = ssGetMexApiInt1(S);
                int_T oPortComplexSignal  = (int_T)ssGetMexApiInt2(S);
                sfcnSetOutputPortComplexSignal(S,port,oPortComplexSignal);
            } else {
                ssSetErrorStatus(S,"Unexpected call to "
                                 "mdlSetOutputPortComplexSignal");
            }
            break;

          case SS_CALL_MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS:
            if (ssGetmdlSetDefaultPortComplexSignals(S) != NULL) {
                sfcnSetDefaultPortComplexSignals(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to "
                                 "mdlSetDefaultPortComplexSignals");
            }
            break;

          case SS_CALL_MDL_SET_INPUT_PORT_FRAME_DATA:
            if (ssGetmdlSetInputPortFrameData(S) != NULL) {
                int_T   port               = ssGetMexApiInt1(S);
                Frame_T inputPortFrameData = (Frame_T)ssGetMexApiInt2(S);
                sfcnSetInputPortFrameData(S,port,inputPortFrameData);
            } else {
                ssSetErrorStatus(S, "Unexpected call to "
                                 "mdlSetInputPortFrameData");
            }
            break;

#         endif

          case SS_CALL_MDL_INITIALIZE_SAMPLE_TIMES:
            mdlInitializeSampleTimes(S);
            break;

          case SS_CALL_MDL_SET_WORK_WIDTHS:
            if (ssGetmdlSetWorkWidths(S) != NULL) {
                sfcnSetWorkWidths(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlSetWorkWidths");
            }
            break;

#         if S_FUNCTION_LEVEL == 2 && defined(MDL_RTW)
          case SS_CALL_MDL_RTW:
            if (ssGetmdlRTW(S) != NULL) {
                sfcnRTW(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlRTW");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 1
          case SS_CALL_MDL_INITIALIZE_CONDITIONS:
            mdlInitializeConditions(ssGetX(S),S);
            break;
#         elif defined(MDL_INITIALIZE_CONDITIONS)
          case SS_CALL_MDL_INITIALIZE_CONDITIONS:
            if (ssGetmdlInitializeConditions(S) != NULL) {
                mdlInitializeConditions(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to "
                                 "mdlInitializeConditions");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2 && defined(MDL_START)
          case SS_CALL_MDL_START:
            if (ssGetmdlStart(S) != NULL) {
                mdlStart(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlStart");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_ENABLE)
          case SS_CALL_RTW_GENERATED_ENABLE:
            if (ssGetRTWGeneratedEnable(S) != NULL) {
                mdlEnable(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlEnable");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2 && defined(RTW_GENERATED_DISABLE)
          case SS_CALL_RTW_GENERATED_DISABLE:
            if (ssGetRTWGeneratedDisable(S) != NULL) {
                mdlDisable(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlDisable");
            }
            break;
#         endif

          case SS_CALL_MDL_CHECK_PARAMETERS:
            if (ssGetmdlCheckParameters(S) != NULL) {
                sfcnCheckParameters(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlCheckParameters");
            }
            break;

#         if S_FUNCTION_LEVEL == 2 && defined(MDL_PROCESS_PARAMETERS)
          case SS_CALL_MDL_PROCESS_PARAMETERS:
            if (ssGetmdlProcessParameters(S) != NULL) {
                sfcnProcessParameters(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlProcessParameters");
            }
            break;
#         endif

          case SS_CALL_MDL_GET_TIME_OF_NEXT_VAR_HIT:
            mdlGetTimeOfNextVarHit(S);
            break;

          case SS_CALL_MDL_OUTPUTS:
#           if S_FUNCTION_LEVEL == 1
                mdlOutputs(ssGetY(S),ssGetX(S),ssGetU(S),S,0);
#           else
                mdlOutputs(S,0);
#           endif
            break;

#         if S_FUNCTION_LEVEL == 1
          case SS_CALL_MDL_UPDATE:
            mdlUpdate(ssGetX(S),ssGetU(S),S,0);
            break;
#         elif defined(MDL_UPDATE)
          case SS_CALL_MDL_UPDATE:
            if (ssGetmdlUpdate(S) != NULL) {
                mdlUpdate(S,0);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlUpdate");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 1
          case SS_CALL_MDL_DERIVATIVES:
            mdlDerivatives(ssGetdX(S),ssGetX(S),ssGetU(S),S,0);
            break;
#         elif defined(MDL_DERIVATIVES)
          case SS_CALL_MDL_DERIVATIVES:
            if (ssGetmdlDerivatives(S) != NULL) {
                mdlDerivatives(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlDerivatives");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2 && defined(MDL_JACOBIAN)
	  case SS_CALL_MDL_JACOBIAN:
            if (ssGetmdlJacobian(S) != NULL) {
                mdlJacobian(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlJacobian");
            }
            break;
#         endif

#         if S_FUNCTION_LEVEL == 2 && defined(MDL_PROJECTION)
	  case SS_CALL_MDL_PROJECTION:
            if (ssGetmdlProjection(S) != NULL) {
                mdlProjection(S);
            } else {
                ssSetErrorStatus(S,"Unexpected call to mdlProjection");
            }
            break;
#         endif

          case SS_CALL_MDL_ZERO_CROSSINGS:
            mdlZeroCrossings(S);
            break;

          case SS_CALL_MDL_TERMINATE:
            __mdlTerminate(S);
            break;

          default:
            ssSetErrorStatus(S,"Invalid flag encountered in simulink.c");
            break;
        }

    } else {

#ifdef PROCESS_MEX_SFUNCTION_CMD_LINE_CALL
        if(ProcessMexSfunctionCmdLineCall(nlhs,plhs,nrhs,prhs)) {
            return;
        }
#endif
        _ProcessMexSfunctionCmdLineCall(nlhs,plhs,nrhs,prhs);
    }

} /* end mexFunction */



/* EOF simulink.c */
