/*
 * SZEROFI2  S-function which increases the sampling rate of a signal
 *           by inserting zeros into the signal.
 * DSP Blockset S-Function for zero filling input.
 *	This SIMULINK S-function inserts zeros between input elements of the
 *	scalar input, creating a "zero-filled" signal at a faster rate;
 *	it is called by the Zero Fill block in the DSP Blockset.
 *  This S-Function based largely on "szerofil.c".
 *
 *  Copyright 1995-2000 The MathWorks, Inc.
 *  $Revision: 1.16 $  $Date: 2000/06/14 14:28:02 $
 */

#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME szerofi2

#define DATA_TYPES_IMPLEMENTED

#include "dsp_sim.h"

enum {INPORT=0}; 
enum {OUTPORT=0}; 

enum {COUNT_IDX=0, NUM_DWORK};

enum {SAMPLETIME_ARGC=0, CONVFACTOR_ARGC, PHASE_ARGC, NUM_ARGS};

#define SAMPLETIME_ARG  (ssGetSFcnParam(S,SAMPLETIME_ARGC)) 
#define CONVFACTOR_ARG  (ssGetSFcnParam(S,CONVFACTOR_ARGC)) 
#define PHASE_ARG       (ssGetSFcnParam(S,PHASE_ARGC))      


#ifdef MATLAB_MEX_FILE
#define MDL_CHECK_PARAMETERS
static void mdlCheckParameters(SimStruct *S) 
{
    static char *msg;
    real_T convfactor_dbl, phase_dbl;
    int_T  convfactor_int, phase_int;

    msg = NULL;

    /* Input sample time */
    if ( (mxGetM(SAMPLETIME_ARG) != 1) ||
         ((mxGetN(SAMPLETIME_ARG) != 1) && (mxGetN(SAMPLETIME_ARG) != 2)) ) {
        msg = "The sample time must be either a scalar or 2-element row vector";
        goto FCN_EXIT;
    }
    if ((mxGetN(SAMPLETIME_ARG) == 2) &&
        (mxGetPr(SAMPLETIME_ARG)[1] != (real_T)0.0)) {
        msg = "Non-zero sample time offset not supported";
        goto FCN_EXIT;
    }
    if (mxGetPr(SAMPLETIME_ARG)[0] <= (real_T)0.0) {
        msg = "Block must have a discrete sample time > 0";
        goto FCN_EXIT;
    }

    /* Upsample factor */
    if (mxGetNumberOfElements(CONVFACTOR_ARG) != 1) {
        msg = "Sample rate conversion factor must be a scalar";
        goto FCN_EXIT;
    }

    convfactor_dbl = mxGetPr(CONVFACTOR_ARG)[0];
    convfactor_int = (int_T)convfactor_dbl;
    if ((convfactor_dbl != convfactor_int) ||
        (convfactor_dbl <= (real_T)0.0)) {
        msg = "Sample rate conversion factor must be an integer > 0";
        goto FCN_EXIT;
    }

    /* Sample offset */
    if (mxGetNumberOfElements(PHASE_ARG) != 1) {
        msg = "Phase must be a scalar";
        goto FCN_EXIT;
    }
    phase_dbl = mxGetPr(PHASE_ARG)[0];
    phase_int = (int_T)phase_dbl;

    if (phase_dbl != phase_int) {
        msg = "Sample offset must be an integer";
        goto FCN_EXIT;
    }
    if ((phase_int < 0) || (phase_int > convfactor_int-1)) {
        msg = "Sample offset must be an integer in the range [0:N-1]";
        goto FCN_EXIT;
    }

FCN_EXIT:
    if (msg != NULL) {
        ssSetErrorStatus(S,msg);
    }
}
#endif


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

#if defined(MATLAB_MEX_FILE)
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) return;
    mdlCheckParameters(S);
    if (ssGetErrorStatus(S) != NULL) return;
#endif

    /* Inputs: */
    if (!ssSetNumInputPorts(S, 1)) return;

    ssSetInputPortWidth(            S, INPORT, DYNAMICALLY_SIZED);
    ssSetInputPortDirectFeedThrough(S, INPORT, 1);
    ssSetInputPortComplexSignal(    S, INPORT, COMPLEX_INHERITED);

    /* Outputs: */
    if (!ssSetNumOutputPorts(S,1)) return;

    ssSetOutputPortWidth(        S, OUTPORT, DYNAMICALLY_SIZED);
    ssSetOutputPortComplexSignal(S, OUTPORT, COMPLEX_INHERITED);

    if(!ssSetNumDWork(      S, NUM_DWORK)) return;
    ssSetDWorkWidth(        S, COUNT_IDX, 1);
    ssSetDWorkDataType(     S, COUNT_IDX, SS_INT32);
    ssSetDWorkComplexSignal(S, COUNT_IDX, COMPLEX_NO);

    ssSetNumSampleTimes(    S, 1);
    ssSetOptions(           S, SS_OPTION_EXCEPTION_FREE_CODE);
}


static void mdlInitializeSampleTimes(SimStruct *S)
{
    /* NOTE: Non-zero sample time offsets are not supported.
     *       This condition is tested and an appropriate error
     *       msg generated by mdlCheckParameters().
     */
    const real_T tsi        = mxGetPr(SAMPLETIME_ARG)[0];
    const real_T convfactor = mxGetPr(CONVFACTOR_ARG)[0];
    const real_T tso        = tsi/convfactor;

    ssSetSampleTime(S, 0, tso);
    ssSetOffsetTime(S, 0, 0.0);
}


#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct *S)
{
    int32_T *count = (int32_T *)ssGetDWork(S, COUNT_IDX);
    *count = 0;
}


static void mdlOutputs(SimStruct *S, int_T tid)
{
    const boolean_T  c0    = (boolean_T)(ssGetInputPortComplexSignal(S,INPORT) == COMPLEX_YES);
    const int32_T    phase = (int32_T)(mxGetPr(PHASE_ARG)[0]);
    int_T            width = ssGetInputPortWidth(S,INPORT);
    int32_T         *count = (int32_T *)ssGetDWork(S, COUNT_IDX);

    if (!c0) {
        /* Real: */
        InputRealPtrsType  uptr = ssGetInputPortRealSignalPtrs(S,INPORT);
        real_T            *y    = ssGetOutputPortRealSignal(S,OUTPORT);

        if ((*count)++ == phase) {
            /* Copy the input: */
            while (width-- > 0) {
                *y++ = **(uptr++);
            }

        } else {
            /* Upsample: output zeros (at the fast rate): */
            while(width-- > 0) {
                *y++ = 0.0;
            }
        }
	
    } else {
        /* Complex: */
	InputPtrsType  uptr = ssGetInputPortSignalPtrs(S,INPORT);
        creal_T	      *y    = (creal_T *)ssGetOutputPortSignal(S,OUTPORT);
 
        if ((*count)++ == phase) {
	    /* Copy the input: */
            while (width-- > 0) {
                *y++ = *((creal_T *)(*uptr++));
	    }

	} else {
            /* Upsample: output zeros (at the fast rate): */
            const creal_T czero = {0.0, 0.0};
            while(width-- > 0) {
                *y++ = czero;
            }
	}
    }   

    {
        const int32_T convfactor = (int32_T)(mxGetPr(CONVFACTOR_ARG)[0]);
        *count %= convfactor; /* wrap count */
    }
}


static void mdlTerminate(SimStruct *S)
{
}

#include "dsp_cplxhs11.c"   

#include "dsp_trailer.c"
 
/* [EOF]: szerofi2.c */
