/*
 * SFUN_CPLX.c complex signal example. 
 *
 *   C-MEX S-function for complex signal add with one input port and 
 *   one parameter.
 *
 *
 *   Input        parameter     output
 *   --------------------------------
 *   scalar       scalar        scalar
 *   scalar       1-D vector    1-D vector
 *   1-D vector   scalar        1-D vector
 *   1-D vector   1-D vector    1-D vector
 *
 *
 *   Input        parameter     output
 *   --------------------------------
 *   real         real          real
 *   real         complex       complex
 *   complex      real          complex
 *   complex      complex       complex
 *
 *
 *  Author: M. Shakeri
 *  Copyright 1990-2000 The MathWorks, Inc.
 *  $Revision: 1.1 $  $Date: 2000/07/05 12:34:58 $
 */
#define S_FUNCTION_NAME  sfun_cplx
#define S_FUNCTION_LEVEL 2

#include "simstruc.h"

/* use utility function IsRealMatrix() */
#if defined(MATLAB_MEX_FILE)
#include "sfun_slutils.h"
#endif

enum {PARAM = 0, NUM_PARAMS};

#define PARAM_ARG ssGetSFcnParam(S, PARAM)

#define EDIT_OK(S, ARG) \
       (!((ssGetSimMode(S) == SS_SIMMODE_SIZES_CALL_ONLY) && mxIsEmpty(ARG)))


#ifdef MATLAB_MEX_FILE 
#define MDL_CHECK_PARAMETERS 
/* Function: mdlCheckParameters =============================================
 * Abstract:
 *    Verify parameter settings.
 */
static void mdlCheckParameters(SimStruct *S) 
{
    if(EDIT_OK(S, PARAM_ARG)){
        /* Non-empty, double, real or complex vector */
        if( mxIsEmpty(PARAM_ARG)     || 
            !IsDoubleVect(PARAM_ARG)){
            ssSetErrorStatus(S, "Invalid parameter specified. The parameter "
                             "must be a non-empty, double, real or complex "
                             "vector.");
            return;
        }      
    }
} /* mdlCheckParameters */
#endif 

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *   Initialize the sizes array
 */
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, NUM_PARAMS);

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

    /* Set number of input and output ports */
    if (!ssSetNumInputPorts(S, 1)) return;
    if (!ssSetNumOutputPorts(S,1)) return;

    /* Set input and output port width. Allow scalar expansion. */
    {
        int_T pWidth = mxGetNumberOfElements(PARAM_ARG);
        int_T uWidth = DYNAMICALLY_SIZED;
        int_T yWidth = (pWidth == 1) ? DYNAMICALLY_SIZED : pWidth;

        ssSetInputPortWidth( S, 0, uWidth);
        ssSetOutputPortWidth(S, 0, yWidth);
    }

    /* Set input and output port complex flag */
    {
        boolean_T pIsComplex = mxIsComplex(PARAM_ARG);
        CSignal_T uCplxFlag  = COMPLEX_INHERITED;
        CSignal_T yCplxFlag  = (pIsComplex) ? COMPLEX_YES : COMPLEX_INHERITED;

        ssSetInputPortComplexSignal( S, 0, uCplxFlag);
        ssSetOutputPortComplexSignal(S, 0, yCplxFlag);
    }

    ssSetInputPortDirectFeedThrough(S, 0, 1);

    ssSetNumSampleTimes(S, 1);
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE |
                 SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSION);
} /* mdlInitializeSizes */

/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    Initialize the sample times array.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
}/* mdlInitializeSampleTimes */

/* Function: mdlOutputs =======================================================
 * Abstract:
 *   Compute the outputs of the S-function.
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    boolean_T   uIsComplex = ssGetInputPortComplexSignal (S, 0) == COMPLEX_YES;
    boolean_T   yIsComplex = ssGetOutputPortComplexSignal(S, 0) == COMPLEX_YES;
    boolean_T   pIsComplex = mxIsComplex(PARAM_ARG);


    InputRealPtrsType uPtr   = ssGetInputPortRealSignalPtrs(S,0);  
    real_T            *y     = ssGetOutputPortRealSignal(S,0);
    const real_T      *pr    = mxGetPr(PARAM_ARG);          
    const real_T      *pi    = mxGetPi(PARAM_ARG);

    int_T             uWidth = ssGetInputPortWidth(S,0);
    int_T             pWidth = mxGetNumberOfElements(PARAM_ARG);
    int_T             yWidth = ssGetOutputPortWidth(S,0);

    int               i;

    UNUSED_ARG(tid); /* not used in single tasking mode */

    /*
     * Notes:
     *  - Input complex signal elements are interleaved.
     *  - Output complex signal elements are interleaved.
     *    Example: [1+2i 3+4i] is stored as follows: [1 2 3 4]
     *
     *  - Real and imag parts of parameter are stored separately.
     *    Example: [1+2i 3+4i]
     *             mxGetPr: [1 3]
     *             mxGetPi: [2 4]
     */

    for (i = 0; i < yWidth; i++) {
        /* Add real part */
        int_T uIdx = (uWidth == 1) ? 0 : i;
        int_T pIdx = (pWidth == 1) ? 0 : i;
        int_T yIdx = (yIsComplex)  ? 2*i : i;

        y[yIdx] = *uPtr[uIdx] + pr[pIdx];
        /* Add imag part */
        if(yIsComplex){
            real_T uVal = (uIsComplex) ? *(uPtr[uIdx] + 1) : 0;
            real_T pVal = (pIsComplex) ? pi[pIdx] : 0;

             y[yIdx+1] = uVal + pVal;
        }
    } 
} /* mdlOutputs */


#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_COMPLEX_SIGNAL
/* Function: mdlSetInputPortComplexSignal ======================================
 *    This routine is called with the candidate complex signal flag for a 
 *    dynamically typed port.  If the proposed complex signal flag is 
 *    acceptable, the routine should go ahead and set the actual port 
 *    complex signal flag using ssSetInputPortComplexSignal. If the complex 
 *    signal flag is unacceptable an error should be generated via 
 *    ssSetErrorStatus.  Note that any other dynamically typed input or 
 *    output ports whose complex signal flags are implicitly defined by virtue 
 *    of knowing the complex signal flags of the given port can also have 
 *    their complex signal flags set via calls to ssSetInputPortComplexSignal 
 *    or ssSetOutputPortComplexSignal.
 */
static void mdlSetInputPortComplexSignal(SimStruct  *S, 
                                         int_T      port,
                                         CSignal_T  csig)
{
    CSignal_T yCplxFlag = ssGetOutputPortComplexSignal(S, 0);
    ssSetInputPortComplexSignal(S, port, csig);
    if(yCplxFlag == COMPLEX_INHERITED){
        /* 
         * Block must have a real (non-complex) parameter.
         * Input and output complex flags are the same.
         */
        ssSetOutputPortComplexSignal(S, 0, csig);
    }
}/* mdlSetInputPortComplexSignal */

#define MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL
/* Function: mdlSetOutputPortComplexSignal =====================================
 *    This routine is called with the candidate complex signal flag for a 
 *    dynamically typed port.  If the proposed complex signal flag is 
 *    acceptable, the routine should go ahead and set the actual port 
 *    complex signal flag using ssSetOutputPortComplexSignal. If the complex 
 *    signal flag is unacceptable an error should be generated via 
 *    ssSetErrorStatus.  Note that any other dynamically typed input or 
 *    output ports whose complex signal flags are implicitly defined by virtue 
 *    of knowing the complex signal flags of the given port can also have 
 *    their complex signal flags set via calls to ssSetInputPortComplexSignal 
 *    or ssSetOutputPortComplexSignal.
 */
static void mdlSetOutputPortComplexSignal(SimStruct  *S, 
                                         int_T       port,
                                         CSignal_T   csig)
{
    /*
     * Simulink calls this function if the output complex flag is unknown.
     * In this case, the block must have a real (non-complex) parameter, and
     * the input and output complex flags are the same.
     */
    ssSetInputPortComplexSignal( S, port, csig);
    ssSetOutputPortComplexSignal(S, port, csig);
} /* mdlSetOutputPortComplexSignal */

#define MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS
/* Function: mdlSetDefaultPortComplexSignals ===================================
 *    This routine is called when Simulink is not able to find a candidate 
 *    complex signal flags for dynamically typed ports. This usually happens
 *    when the block is unconnedted or it is in a feedback loop. This routine
 *    must set the complex signal flag of all dynamically typed ports.
 */
static void mdlSetDefaultPortComplexSignals(SimStruct  *S)
{
    CSignal_T uCmplxFlag = ssGetInputPortComplexSignal( S, 0);
    CSignal_T yCmplxFlag = ssGetOutputPortComplexSignal(S, 0);

    if(uCmplxFlag == COMPLEX_INHERITED) {
        ssSetInputPortComplexSignal( S, 0, COMPLEX_NO);
    }

    if(yCmplxFlag == COMPLEX_INHERITED) {
        ssSetOutputPortComplexSignal(S, 0, COMPLEX_NO);
    }
} /* mdlSetDefaultPortComplexSignals */
#endif

/* Function: mdlTerminate =====================================================
 * Abstract:
 *    Called when the simulation is terminated.
 */
static void mdlTerminate(SimStruct *S)
{
    UNUSED_ARG(S); /* unused input argument */
}/* mdlTerminate */

#if defined(MATLAB_MEX_FILE) || defined(NRT)
#define MDL_RTW
/* Function: mdlRTW ============================================================
 * Abstract:
 *    Write block parameters.
 */
static void mdlRTW(SimStruct *S)
{
    boolean_T pIsComplx = mxIsComplex(PARAM_ARG);
    real_T    *pr       = mxGetPr(PARAM_ARG);
    real_T    *pi       = mxGetPi(PARAM_ARG);
    int_T     numElms   = mxGetNumberOfElements(PARAM_ARG);
    
    if (!ssWriteRTWParameters(S, 1,
                              SSWRITE_VALUE_DTYPE_ML_VECT,
                              "Operand",
                              "Operand",
                              pr,
                              pi,
                              numElms,
                              DTINFO(SS_DOUBLE, pIsComplx))){ 
        return;
    }
} /* mdlRTW */
#endif


#ifdef	MATLAB_MEX_FILE    
#include "simulink.c"      
#else
#include "cg_sfun.h"       
#endif

/* [EOF] sfun_matadd.c */
