/*
 * SFFT  FFT S-function.
 * DSP Blockset S-Function to perform an FFT.
 * This SIMULINK S-function computes the FFT of the input vector;
 * it is called by the FFT blocks in the DSP Blockset.
 * It uses a Cooley-Tukey radix-2, decimation-in-frequency
 * FFT algorithm.
 *
 *  Copyright 1995-2000 The MathWorks, Inc.
 *  $Revision: 1.11 $  $Date: 2000/05/05 20:16:10 $
 */

#define S_FUNCTION_NAME sfft

#include <math.h>
#include <string.h>

#include "dsp_sim.h"
#include "fft_rt.h"

#define SAMPLE_TIME ssGetArg(S,0)
#define NUM_ARGS    1

#ifdef MATLAB_MEX_FILE
#define MDL_CHECK_PARAMETERS
static void mdlCheckParameters(SimStruct *S) {
    int_T M = mxGetM(SAMPLE_TIME);
    int_T N = mxGetN(SAMPLE_TIME);

    if ( (M != 1) || ((N != 1) && (N != 2)) ) {
        THROW_ERROR(S, "The sample time must be a "
                            "scalar or a 2-element row vector");
    }
}
#endif


static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, NUM_ARGS);

#if defined(MATLAB_MEX_FILE)
    if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
        mdlCheckParameters(S);
        if (ssGetErrorStatus(S) != NULL) {
            return;
        }
    } else {
        return; /* Simulink will report a parameter mismatch error */
    }
#endif

    ssSetNumInputs(        S, DYNAMICALLY_SIZED);
    ssSetNumOutputs(       S, DYNAMICALLY_SIZED);
    ssSetDirectFeedThrough(S, 1);
    ssSetNumSampleTimes(   S, 1);
    ssSetOptions(          S, SS_OPTION_EXCEPTION_FREE_CODE |
                              SS_OPTION_USING_ssGetUPtrs);
}


static void mdlInitializeSampleTimes(SimStruct *S)
{
    real_T sampleTime;
    real_T offsetTime = 0.0;

    sampleTime = mxGetPr(SAMPLE_TIME)[0];
    if (mxGetN(SAMPLE_TIME) == 2) {
        offsetTime = mxGetPr(SAMPLE_TIME)[1];
    }
    ssSetSampleTimeEvent(S, 0, sampleTime);
    ssSetOffsetTimeEvent(S, 0, offsetTime);
}


static void mdlInitializeConditions(real_T *x0, SimStruct *S)
{
#ifdef MATLAB_MEX_FILE
    /*
     * Check to make sure input size is a power of 2:
     */
    int_T numinputs = ssGetNumInputs(S);
    if (numinputs != -1) {
	int_T dummy;
	if (frexp((real_T)numinputs, &dummy) != 0.5) {
            ssSetErrorStatus(S,"Width of input to FFT must be a power of 2");
            return;
	}
	if (numinputs == 1) {
	  mexWarnMsgTxt("Computing the FFT of a scalar input.\n");
	}
    }
#endif /* MATLAB_MEX_FILE */
}


static void mdlOutputs(real_T *y, const real_T *x, const real_T *u, 
                       SimStruct *S, int_T tid)
{
      if (ssIsMajorTimeStep(S)) {
        UPtrsType uptr      = ssGetUPtrs(S);
        int_T     numInputs = ssGetNumInputs(S);
        int_T     Nfft      = numInputs/2;
        int_T     i;

	/* Copy inputs into outputs, since FFT operates in place: */
        for (i=0; i<numInputs; i++) {
            y[i] = **(uptr++);
        }
	fft(Nfft, y, y+Nfft);
    }
}


static void mdlUpdate(real_T *x, const real_T *u, SimStruct *S, int_T tid)
{
}


static void mdlDerivatives(real_T *dx, const real_T *x, const real_T *u, 
                           SimStruct *S, int_T tid)
{
}


static void mdlTerminate(SimStruct *S)
{
}

#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
