/*
 *  dsp_sim.h
 *  CMEX S-Fcn simulation support library for DSP Blockset
 *
 *  Copyright 2000 The MathWorks, Inc.
 *  $Revision: 1.9 $ $Date: 2000/08/15 20:08:54 $
 */

#ifndef dsp_sim_h
#define dsp_sim_h

#include "dsp_rt.h"   /* run-time support     */
#include "simstruc.h" /* simulation-only code */
#include "dsp_ic.h"   /* simulation IC handling */

/*
 * ----------------------------------------------------------
 * Error handling
 * ----------------------------------------------------------
 */
#define THROW_ERROR(S,MSG) {ssSetErrorStatus(S,MSG); return;}
#define ANY_ERRORS(S)      (ssGetErrorStatus(S) != NULL)
#define RETURN_IF_ERROR(S) {if (ANY_ERRORS(S)) return;}

/*
 * Source located in dsplib.c:
 */
extern boolean_T registerSFunctionParams(SimStruct *S, int_T numParams);


/*
 * Use as first line in mdlInitializeSizes(), eg:
 *
 *  static void mdlInitializeSizes(SimStruct *S)
 *  {
 *      REGISTER_SFCN_PARAMS(S, NUM_ARGS)
 *      ...
 *  }
 */
#define REGISTER_SFCN_PARAMS(S, numParams) {if(!registerSFunctionParams(S, numParams)) return;}


/*
 * ----------------------------------------------------------
 * Input argument processing
 * ----------------------------------------------------------
 */

/*
 * NOTE: For Simulink, our definition of a vector does NOT include
 *       N-D or an "empty" vector.  Ex: 1x5 is a vector, 0x5 is not.
 */
#define IS_SCALAR(X)        (mxGetNumberOfElements(X) == 1)
#define IS_VECTOR(X)        ((mxGetM(X) == 1) || (mxGetN(X) == 1))
#define IS_ROW_VECTOR(X)    ((mxGetM(X) == 1) && (mxGetN(X) > 1 ))
#define IS_COLUMN_VECTOR(X) ((mxGetM(X) > 1 ) && (mxGetN(X) == 1))

#define IS_DOUBLE(X) (!mxIsComplex(X) && !mxIsSparse(X) && mxIsDouble(X))

#define IS_SCALAR_DOUBLE(X) (IS_DOUBLE(X) && IS_SCALAR(X))
#define IS_VECTOR_DOUBLE(X) (IS_DOUBLE(X) && IS_VECTOR(X))

/* Check that the scalar double is in a certain range: */
#define IS_SCALAR_DOUBLE_GREATER_THAN(X,V) (IS_SCALAR_DOUBLE(X) && (mxGetPr(X)[0] >  (real_T)V))
#define IS_SCALAR_DOUBLE_GE(X,V)           (IS_SCALAR_DOUBLE(X) && (mxGetPr(X)[0] >= (real_T)V))

/* Check an element of a vector: */
#define IS_IDX_FLINT(X,IDX) (IS_DOUBLE(X) && \
                    (IDX < mxGetNumberOfElements(X)) && \
                    (IDX >= 0) && \
                    !mxIsInf(mxGetPr(X)[IDX]) && \
                    !mxIsNaN(mxGetPr(X)[IDX]) && \
                    (mxGetPr(X)[IDX] == floor(mxGetPr(X)[IDX])))

#define IS_IDX_FLINT_GE(X,IDX,V) (IS_IDX_FLINT(X,IDX) && \
                                    (mxGetPr(X)[IDX] >= (real_T)V))


#define IS_IDX_FLINT_IN_RANGE(X,IDX,A,B) (IS_IDX_FLINT(X,IDX) && \
                           (mxGetPr(X)[IDX] >= (real_T)A) && \
                           (mxGetPr(X)[IDX] <= (real_T)B) )

/* Check if arg is a floating-point integer-valued scalar (a "flint"): */
#define IS_FLINT(X)              (IS_SCALAR(X) && IS_IDX_FLINT(X,0))
#define IS_FLINT_GE(X,V)         (IS_SCALAR(X) && IS_IDX_FLINT_GE(X,0,V)) 
#define IS_FLINT_IN_RANGE(X,A,B) (IS_SCALAR(X) && IS_IDX_FLINT_IN_RANGE(X,0,A,B))

/* Use to validate general initial conditions argument
 * May be an empty matrix, may not contain doubles.
 */
#define IS_VALID_IC(X) (!mxIsSparse(X) && mxIsNumeric(X))

/*
 * OK_TO_CHECK_VAR is used to determine if the contents of an
 *   "edit"-style mask dialog box should be checked in
 *   the mdlCheckParameters section of a CMEX S-Function.
 *   Edit boxes may contain variables instead of constants,
 *   and those variables might not be defined in the workspace
 *   at "dialog apply" time.  This should not be an error, so
 *   the dialog parameter should not be checked unless the user
 *   is running the simulation.  There is no need to use it for
 *   Checkboxes, Popups, etc.
 *
 * Typical usage:
 *   if OK_TO_CHECK_VAR(S, PARAM1) {
 *      <check PARAM1 content here>
 *   }
 */
#define OK_TO_CHECK_VAR(S, ARG) ((ssGetSimMode(S) != SS_SIMMODE_SIZES_CALL_ONLY) || !mxIsEmpty(ARG))


/*
 * Memory allocation for Simulink S-Functions
 *
 * This function forces the allocation to be persistent,
 * so that MATLAB does not release the allocation when
 * the function that allocates the memory returns.
 *
 * For example, if you called mxCalloc during mdlStart,
 * then at the exit of mdlStart Simulink will free the memory.
 * Thus, if you attempt to use the memory pointer during
 * mdlOutputs, you will be accessing unallocated memory.
 * All C-MEX S-Functions should only call slCalloc/slFree.
 */
extern void *slCalloc(
	SimStruct *S,
	const int_T ,
	const int_T );

extern void slFree(void *ptr);


/*
 * ----------------------------------------------------------
 * Cache functions
 * These must remain macros
 * ----------------------------------------------------------
 */
#define GetSFcnCache(S, SFcnCache) ((SFcnCache *)ssGetUserData(S))

#define CallocSFcnCache(S, SFcnCache)                                \
{                                                                    \
    SFcnCache *cache = (SFcnCache *)slCalloc(S,1,sizeof(SFcnCache)); \
    ssSetUserData(S, cache);                                         \
}

#define FreeSFcnCache(S, SFcnCache)     \
{                                       \
    slFree(GetSFcnCache(S, SFcnCache)); \
    ssSetUserData(S, NULL);             \
}


/* Common simulation-only helper functions */
#include "dsp_dtype_err.h"
#include "dsp_cplx_err.h"
#include "dsp_fixpt_err.h"
#include "dsp_ismultirate_sim.h"
#include "dsp_mtrx_err.h"
#include "dsp_ts_err.h"

#endif  /* dsp_sim_h */

/* [EOF] dsp_sim.h */
