/*
 *  SBUFCONV.c - buffered convolution.
 *  DSP Blockset S-Function to convolve two vectors.
 *  This SIMULINK S-function computes the convolution of the two input 
 *  vectors; it is called by the Convolution blocks in the DSP Blockset.
 *
 *  Copyright 1995-2000 The MathWorks, Inc.
 *  $Revision: 1.10 $ $Date: 2000/05/05 20:15:57 $
 */

#define S_FUNCTION_NAME sbufconv

#include "dsp_sim.h"

#ifndef MIN
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)<(b) ? (b) : (a))
#endif


static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(    S, 0);
    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)
{
    ssSetSampleTimeEvent(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTimeEvent(S, 0, (real_T)0.0);
}


static void mdlInitializeConditions(real_T *x0, SimStruct *S)
{
}


static void mdlOutputs(real_T *y, const real_T *x, const real_T *u, 
                       SimStruct *S, int_T tid)
{
    UPtrsType   uptr = ssGetUPtrs(S);
    const int_T m    = **(uptr++);                /* width of vector #1 */
    const int_T n    = ssGetNumInputs(S) - m - 1; /* width of vector #2 */
    const int_T ylen = m+n-1;
    int_T       i;
    
    for (i = 0; i < ylen; i++) {
      const int_T j_end = MIN(i, m-1);
      real_T      sum   = 0.0;
      int_T       j;

      for (j = MAX(0, i-n+1); j <= j_end; j++) {
	sum += *uptr[j] * *uptr[m+i-j];
      }
      *y++ = sum;
    }
}


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)
{
}


/*
 *  There are 2 more inputs than outputs:
 *   - width of input 1 (inputs are muxed into one port)
 *   - convolution result is of length L+M-1 (one fewer than # input elements)
 */
#if defined(MATLAB_MEX_FILE)
#define MDL_GET_INPUT_PORT_WIDTH
static int_T mdlGetInputPortWidth(SimStruct *S, int_T outputPortWidth)
  {
      return(outputPortWidth+2);
  }

#define MDL_GET_OUTPUT_PORT_WIDTH
static int_T mdlGetOutputPortWidth(SimStruct *S, int_T inputPortWidth)
  {
      return(inputPortWidth-2);
  }
#endif


#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
