/*
*   SCOMPNSEQ2	A sample-time driven Simulink PN Sequence Generator
*
*   Copyright 1996-2000 The MathWorks, Inc.
*   $Revision: 1.2 $  $Date: 2000/08/25 17:01:16 $
*/

#define	S_FUNCTION_NAME	scompnseq2
#define S_FUNCTION_LEVEL 2

#include "simstruc.h"
#include "dsptypes.h"

/* D-work vectors */
enum {SHIFT_REG=0, NUM_DWORKS};

/* Input/Output ports */
enum{NUM_INPORTS=0};
enum {OUTPORT=0, NUM_OUTPORTS};

/* S-fcn parameters */
enum {POLYNOMIAL_ARGC=0, INITIAL_STATE_ARGC, SAMPLE_TIME_ARGC, FRAME_BASED_ARGC, SAMPLES_PER_FRAME_ARGC, NUM_ARGS};

#define POLYNOMIAL_ARG      	ssGetSFcnParam(S, POLYNOMIAL_ARGC)
#define INITIAL_STATE_ARG   	ssGetSFcnParam(S, INITIAL_STATE_ARGC)
#define SAMPLE_TIME_ARG 		ssGetSFcnParam(S, SAMPLE_TIME_ARGC)
#define FRAME_BASED_ARG 		ssGetSFcnParam(S, FRAME_BASED_ARGC)
#define SAMPLES_PER_FRAME_ARG 	ssGetSFcnParam(S, SAMPLES_PER_FRAME_ARGC)

#define BLOCK_BASED_SAMPLE_TIMES		1
#define FRAMEBASED 						(mxGetPr(FRAME_BASED_ARG)[0] != 0.0)

#ifdef MATLAB_MEX_FILE
#define MDL_CHECK_PARAMETERS
static void mdlCheckParameters(SimStruct *S) {
 
	/* Scramble polynomial parameter - real, integer vector */
    if (OK_TO_CHECK_VAR(S, POLYNOMIAL_ARG)) {
        if ( (mxGetNumberOfElements(POLYNOMIAL_ARG) < 2) ||
        	 !mxIsNumeric(POLYNOMIAL_ARG) 				 ||
        	 mxIsSparse(POLYNOMIAL_ARG)
		   ) {
            	THROW_ERROR(S,"The generator polynomial parameter must be a numeric vector.");
        }
    }

    /* Initial state parameter - real, integer vector */
    if (OK_TO_CHECK_VAR(S, INITIAL_STATE_ARG)) {
        if ( (mxGetNumberOfElements(INITIAL_STATE_ARG) < 1) ||
        	 !mxIsNumeric(INITIAL_STATE_ARG) 				||
        	 mxIsSparse(INITIAL_STATE_ARG)
		   ) {
            	THROW_ERROR(S,"The initial state parameter must be numeric.");
        }
    }

    /* Sample Time parameter - real scalar not equal to 0 */
	if (OK_TO_CHECK_VAR(S, SAMPLE_TIME_ARG)) {
	    if ( !mxIsDouble(SAMPLE_TIME_ARG)                  || 
    	     (mxGetNumberOfElements(SAMPLE_TIME_ARG) != 1) ||
    	     mxIsComplex(SAMPLE_TIME_ARG)				   ||
    	     (mxGetPr(SAMPLE_TIME_ARG)[0] == 0 )
       	   ) {
       	   	THROW_ERROR(S,"The sample time parameter must be a real scalar not equal to 0.");
	    }
	}
	
	/* Samples per frame parameter - integer scalar > 0 */
    if (!IS_FLINT_GE(SAMPLES_PER_FRAME_ARG,1)) {
       THROW_ERROR(S, "The number of samples per frame must be an integer-valued scalar greater than 0.");
    }  
}
#endif


static void	mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, NUM_ARGS);
    
#if defined(MATLAB_MEX_FILE)
    if (ssGetNumSFcnParams(S) != NUM_ARGS) return;
    mdlCheckParameters(S);
    if (ssGetErrorStatus(S) != NULL) return;
#endif

    /* All parameters are non-tunable */
    ssSetSFcnParamNotTunable(S, POLYNOMIAL_ARGC);
    ssSetSFcnParamNotTunable(S, INITIAL_STATE_ARGC);
    ssSetSFcnParamNotTunable(S, SAMPLE_TIME_ARGC);
    ssSetSFcnParamNotTunable(S, FRAME_BASED_ARGC);
    ssSetSFcnParamNotTunable(S, SAMPLES_PER_FRAME_ARGC);
    
	/* Port parameters */
	/* No input ports */
    if (!ssSetNumInputPorts(S, NUM_INPORTS)) return;
    
	/* Single output port */
    if (!ssSetNumOutputPorts(S, NUM_OUTPORTS)) return;
    {
		int_T 	  frameSize  = (int_T)mxGetPr(SAMPLES_PER_FRAME_ARG)[0];

		if (FRAMEBASED) {
  	  		ssSetOutputPortFrameData(S, OUTPORT, FRAME_YES);
			ssSetOutputPortMatrixDimensions(S, OUTPORT, frameSize, 1);
  		} else { /* unoriented scalar only */
			ssSetOutputPortFrameData(S, OUTPORT, FRAME_NO);
			ssSetOutputPortVectorDimension(	S, OUTPORT, 1);
  		}
	}
    ssSetOutputPortComplexSignal(S, OUTPORT, COMPLEX_NO);
    ssSetOutputPortReusable(     S, OUTPORT, 1);

    /* Set up sample times: */
    ssSetNumSampleTimes(      S, BLOCK_BASED_SAMPLE_TIMES);    

    if (!ssSetNumDWork(S, DYNAMICALLY_SIZED)) return;
    ssSetOptions( S, SS_OPTION_EXCEPTION_FREE_CODE);
}

static void	mdlInitializeSampleTimes(SimStruct *S)
{
	const real_T  Ts 		   = mxGetPr(SAMPLE_TIME_ARG)[0];
	const int_T  frameSize 	   = (int_T)mxGetPr(SAMPLES_PER_FRAME_ARG)[0];
	
	if (FRAMEBASED) {
		ssSetSampleTime(S, 0, frameSize*Ts);
	} else {
		ssSetSampleTime(S, 0, Ts);
	}
    ssSetOffsetTime(S, 0, 0.0);
}

#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct *S)
{
	int_T	 *shift_reg	    = (int_T *)ssGetDWork(S, SHIFT_REG);
	real_T	 *initial_state	= (real_T *)mxGetPr(INITIAL_STATE_ARG);
	
	int_T    i, polyOrder;
		
	polyOrder = mxGetN(POLYNOMIAL_ARG)	* mxGetM(POLYNOMIAL_ARG) - 1;
	
	/* Set up the Initial states */	
	shift_reg[0] = 0;
	if (mxGetN(INITIAL_STATE_ARG) * mxGetM(INITIAL_STATE_ARG) == polyOrder) {
		for	(i = 0;	i < polyOrder; i++)
		    shift_reg[i] = (int_T)initial_state[i];
	} else { /* scalar expand */
		for	(i = 0;	i < polyOrder; i++)
			shift_reg[i] = (int_T)initial_state[0];
	}
}

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

        int_T	 *shift_reg  = (int_T *)ssGetDWork(S, SHIFT_REG);
		real_T	 *polynomial = (real_T *)mxGetPr(POLYNOMIAL_ARG);
		real_T   *y        	 = (real_T *)ssGetOutputPortRealSignal(S,OUTPORT);

		polyOrder = mxGetN(POLYNOMIAL_ARG)	* mxGetM(POLYNOMIAL_ARG) - 1;			 

		/* compute feedback bit	*/
		tmp	= 0;
		for	(i = 1;	i <= polyOrder; i++) 
		    tmp += (int_T)polynomial[i] * shift_reg[i-1];
		tmp	= tmp %	2;

		/* output data	*/
		y[0] = shift_reg[polyOrder-1];
		
		/* shift */
		for	(i = polyOrder-1; i > 0; i--)
			shift_reg[i] = shift_reg[i-1];
		shift_reg[0] = tmp;
}

static void	mdlTerminate(SimStruct *S)
{
}

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_WORK_WIDTHS
static void mdlSetWorkWidths(SimStruct *S)
{
	int_T polyOrder;
	polyOrder = mxGetN(POLYNOMIAL_ARG) * mxGetM(POLYNOMIAL_ARG) - 1;

    /* Set DWork vector: */ 
	if (!ssSetNumDWork(S, NUM_DWORKS)) return;     /* SHIFT_REG */

    /* Shift Register */
    ssSetDWorkWidth(        S, SHIFT_REG, polyOrder);
    ssSetDWorkDataType(     S, SHIFT_REG, SS_INT32);
    ssSetDWorkComplexSignal(S, SHIFT_REG, COMPLEX_NO);
}
#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
