/*
 * $Revision: 1.5 $
 * $RCSfile: fcncallgen.c,v $
 *
 * Abstract:
 *   Function-call generator block executes function-call subsystems
 *   at the designated rate.
 *     
 * Author:
 *   Pete Szpak
 *
 * Date:
 *   29 Jul 1998
 *
 *  Copyright (c) 1990-1998 by The MathWorks, Inc. All Rights Reserved.
 */

#define S_FUNCTION_NAME  fcncallgen
#define S_FUNCTION_LEVEL 2

#define SAMPLE_TIME      (ssGetSFcnParam(S,0))

#include "simstruc.h"

#ifndef MATLAB_MEX_FILE
/*
 * This file cannot be used directly with the Real-Time Workshop. However,
 * this S-function does work with the Real-Time Workshop via
 * the Target Language Compiler technology. See 
 * matlabroot/toolbox/blocks/tlc_c/fcncallgen.tlc.
 */
# error This_file_can_be_used_only_during_simulation_inside_Simulink
#endif

/*====================*
 * S-function methods *
 *====================*/

/* Function: IsRealScalar ======================================================
 * Abstract:
 *      Verify that the mxArray is a real scalar.
 */
static boolean_T IsRealScalar(const mxArray *m)
{
    if (mxIsNumeric(m) &&
        mxIsDouble(m) &&
        !mxIsLogical(m) &&
        !mxIsComplex(m) &&
        !mxIsSparse(m) &&
        !mxIsEmpty(m) &&
        mxGetNumberOfDimensions(m) == 2 &&
        mxGetM(m) == 1 && mxGetN(m) == 1) {
        
        real_T *data = mxGetPr(m);
        if (!mxIsFinite(data[0])) {
            return(0);
        }
        return(1);
    } else {
        return(0);
    }
}
/* end IsRealScalar */


#define MDL_CHECK_PARAMETERS
static void mdlCheckParameters(SimStruct *S)
{
    /* Note, when the sample time parameter is specified as a variable and
     * it doesn't exist, then the parameter will be []. We don't error
     * out if we are doing a "sizes call only". This is compatible with
     * Simulink.
     */

    if (mxGetNumberOfElements(SAMPLE_TIME) != 0 || 
        ssGetSimMode(S) != SS_SIMMODE_SIZES_CALL_ONLY) {
        real_T sampleTime;

        if (IsRealScalar(SAMPLE_TIME)) {
            sampleTime = (real_T) (*(mxGetPr(SAMPLE_TIME)));
        } else {
            sampleTime = -10.0; /* force error */
        }

        /* sampleTime == -1  : triggered
         * sampleTime == 0   : continuous
         * sampleTime > 0    : discrete
         */
        if (sampleTime < 0.0 && sampleTime != -1.0) {
            ssSetErrorStatus(S, "Invalid sample time.");
            return;
        }
    }
}


static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 1);
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Simulink will report a parameter mismatch error */
    }
    mdlCheckParameters(S);
    ssSetSFcnParamNotTunable(S, 0);

    ssSetNumInputPorts(S, 0);
    ssSetNumOutputPorts(S, 1);
    ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
    ssSetNumSampleTimes(S, 1);
    ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE));
}

static void mdlInitializeSampleTimes(SimStruct *S)
{
    int_T i;
    real_T sampleTime = (real_T) (*(mxGetPr(SAMPLE_TIME)));
    
    ssSetSampleTime(S, 0, sampleTime);
    ssSetOffsetTime(S, 0, 0.0);
    
    for(i = 0; i < ssGetOutputPortWidth(S,0); i++) {
        ssSetCallSystemOutput(S,i);
    }
}

static void mdlOutputs(SimStruct *S, int_T tid)
{
    int_T i;

    for(i = 0; i < ssGetOutputPortWidth(S,0); i++) {
        if (!ssCallSystemWithTid(S,i,0)) {
            return; /* error handled by Simulink */
        }
    }
}

static void mdlTerminate(SimStruct *S) {}

#define MDL_RTW
static void mdlRTW(SimStruct *S) {}


#ifdef  MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif

/* EOF: fcncallgen.c */
