/*  File    : sfunmem.c
 *  Abstract:
 *
 *      A one integration-step delay and hold "memory" function.
 *
 *      Syntax:  [sys, x0] = sfunmem(t,x,u,flag)
 *
 *      This file designed to be used in a Simulink S-Function block.
 *      It performs a one integration-step delay and hold "memory" function.
 *      Thus, no matter how large or small the last time increment was in
 *      the integration process, this function will hold the input variable
 *      from the last integration step.
 *
 *      Use this function with a clock as input to get the step-size at each
 *      step of a simulation.
 *
 *      For more details about S-functions, see simulink/src/sfuntmpl_doc.c
 *
 *  Copyright 1990-2000 The MathWorks, Inc.
 *  $Revision: 1.12 $
 */

#define S_FUNCTION_NAME sfunmem
#define S_FUNCTION_LEVEL 2

#include <string.h>
#include "simstruc.h"

#define U(element) (*uPtrs[element])  /* Pointer to Input Port0 */

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

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *    Call mdlCheckParameters to verify that the parameters are okay,
 *    then setup sizes of the various vectors.
 */
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Parameter mismatch will be reported by Simulink */
    }

    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth (S, 0, DYNAMICALLY_SIZED);
    ssSetInputPortDirectFeedThrough(S, 0, 0);

    if (!ssSetNumOutputPorts(S, 1)) return;
    ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);

    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, DYNAMICALLY_SIZED);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);

    /* Take care when specifying exception free code - see sfuntmpl_doc.c */
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}



/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    S-function is continuous, fixed in minor time steps.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, FIXED_IN_MINOR_STEP_OFFSET);
}



#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
 * Abstract:
 *    The memory state is stored in the RWork vector, initialize it to zero
 */
static void mdlInitializeConditions(SimStruct *S)
{
    real_T *rwork = ssGetRWork(S);
    int_T  i;
 
    for (i = 0; i < ssGetNumRWork(S); i++) {
        rwork[i] = 0.0;
    }
}
 
 

/* Function: mdlOutputs =======================================================
 * Abstract:
 *
 *      y = rwork
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    real_T *y     = ssGetOutputPortRealSignal(S,0);
    real_T *rwork = ssGetRWork(S);
    int_T  i;
 
    UNUSED_ARG(tid); /* not used in single tasking mode */

    /* Output the last input, which is stored in the real work vector */
    for (i = 0; i < ssGetNumRWork(S); i++) {
        y[i] = rwork[i];
    }
}



#define MDL_UPDATE
/* Function: mdlUpdate ========================================================
 * Abstract:
 *    This function is called once for every major integration time step.
 *    Discrete states are typically updated here, but this function is useful
 *    for performing any tasks that should only take place once per integration
 *    step.
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
    InputRealPtrsType uPtrs  = ssGetInputPortRealSignalPtrs(S,0);
    real_T            *rwork = ssGetRWork(S);
    int_T             i;
 
    UNUSED_ARG(tid); /* not used in single tasking mode */

    /* Just set memory to last input */
    for (i = 0; i < ssGetNumRWork(S); i++) {
        rwork[i] = U(i);
    }
}



/* Function: mdlTerminate ===================================================== * Abstract:
 *    No termination needed, but we are required to have this routine.
 */
static void mdlTerminate(SimStruct *S)
{
    UNUSED_ARG(S); /* unused input argument */
}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif
