/* 
 * dsp_ic.c
 *
 *  Author: R. Firtion
 *  Copyright (c) 1995-2000 The MathWorks, Inc.
 *  $Revision: 1.3 $  $Date: 2000/07/25 15:54:39 $
 *
 * Abstract:
 *   Initial condition handler.
 */

#if 0
/**********************/
/*** Typical usage: ***/
/**********************/

0. #include "dsp_sim.h"
   link against "dsp_sim.obj" (made from "dsp_sim.c")

1. Put this into the clients S-Fcn cache:

    typedef struct {
        int_T blahblah;

        CopyICsCache ic_cache;

        int_T blahblah2;
    } SFcnCache;


2. From mdlStart, initialize the IC system:

    initCopyICsFcn(S, &(sfcn_cache->ic_cache), IC_ARG(S), dworkNum, portNum, nChans, fcnID);

    fcnID is the function of ID of the copy ICs functions to be used.
        see sdspvidly2.c for an example.

3. Use it!  From mdlInitializeConditions (or wherever ICs need to be used),

    SFcnCache sfcn_cache = ssGetUserData(S);
    COPY_THE_ICs(sfcn_cache->ic_cache);

4. Deallocate sfcn cache

5. For TLC, follow the instructions in dsp_ic.tlc

/**********************/
#endif


#include "dsp_sim.h" /* for OK_TO_CHECK_VAR macro, etc. */

/* Uncomment line below to display debug information. */
/* #define DEBUG */

/*
 * ---------------------------------------------------------------------------
 * IC error checking:
 * ---------------------------------------------------------------------------
 */

void validateICs(
    SimStruct     *S,
    const mxArray *ICs,
    const int_T    portNum
    )
{
    const int_T numDims = mxGetNumberOfDimensions(ICs);

    if (numDims > 3) {
        THROW_ERROR(S, "The maximum dimensionality for the initial condition "
                        "matrix is three.");
    }
    if (mxIsComplex(ICs) && isInputReal(S, portNum)) {
        THROW_ERROR(S,"Use real initial conditions with real data.");
    }

    if (OK_TO_CHECK_VAR(S, ICs)) {
        if (!IS_VALID_IC(ICs)) {
            THROW_ERROR(S, "The initial conditions must be numeric.  No strings, cell arrays, etc");
        }
    }
}

/*
 * ---------------------------------------------------------------------------
 * IC argument cache
 * ---------------------------------------------------------------------------
 */

static void fillInCopyICsArgs(
    SimStruct             *S,
    TMWDSP_CopyICsFcnArgs *args,
    const mxArray         *ICs,
    const int_T            dworkNum, /* member of args struct */
    
    /* members of args struct*/
    const int_T portNum,
    const int_T nChans
    )
{
    args->nChans              = nChans;
    args->dWorkRows           = ssGetDWorkWidth(S,dworkNum)/nChans;
    args->numICs              = mxGetNumberOfElements(ICs);
    args->portNum             = portNum;
    args->dataPortWidth       = ssGetInputPortWidth(S, args->portNum);
    args->bytesPerRealElement = ssGetDataTypeSize(S, ssGetInputPortDataType(S,args->portNum));
    args->prIC                = (byte_T *)mxGetPr(ICs);
    args->piIC                = (byte_T *)mxGetPi(ICs);
    args->buffer              = (byte_T *)ssGetDWork(S,dworkNum);
}


#ifdef DEBUG
void displayCopyICsFcnArgs(SimStruct *S, TMWDSP_CopyICsFcnArgs *args)
{
    mexPrintf("Argument ic_cache: "
        "nChans=%d, dWorkRows=%d, numICs=%d, "
        "portNum=%d, dataPortWidth=%d, bytesPerRealEle=%d\n",
        args->nChans, args->dWorkRows, args->numICs,
        args->portNum, args->dataPortWidth, args->bytesPerRealElement);
}
#endif


static void fillInCopyICsFcn(
    SimStruct     *S,
    CopyICsCache  *ic_cache,
    const mxArray *ICs,
    int_T          fcnID
    )
{
    static const CopyICsFcn CopyICsFcnTable[] = {

        CopyScalarICsRealToReal,
        CopyScalarICsRealToComplex,
        CopyScalarICsComplexToComplex,

        CopyVectorICsRealToReal,
        CopyVectorICsRealToComplex,
        CopyVectorICsComplexToComplex,
        
        Copy3DSampleMatrixICsRealToReal,
        Copy3DSampleMatrixICsRealToComplex,
        Copy3DSampleMatrixICsComplexToComplex,    

        Copy3DFrameMatrixICsRealToReal,
        Copy3DFrameMatrixICsRealToComplex,
        Copy3DFrameMatrixICsComplexToComplex    
    };

    const boolean_T  complexInput = isInputComplex(S,ic_cache->args.portNum);
    const boolean_T  complexICs   = mxIsComplex(ICs);

    /* Which of the 3 complexity situations (RR,RC,CC) (0-2)
     * Which of the 4 clusters (scalar/row/etc)        (0-3) */

    /* The S-function is responsible for interpreting the IC vector correctly (fcnID):
     * 
     * 0 == Scalar
     * 1 == Vector ICs
     * 2 == 3D Sample Matrix
     * 3 == 3D Frame Matrix
     */

    int_T clusterIdx = fcnID;
    int_T complexIdx = (complexICs) ? 2 : (complexInput ? 1 : 0);

    ic_cache->fcnIdx = complexIdx + 3*clusterIdx;
    ic_cache->fcn    = CopyICsFcnTable[ic_cache->fcnIdx];
}

#ifdef DEBUG
void displayCopyICsFcn(SimStruct *S, CopyICsCache *ic_cache)
{
    static const char *mode_str[] = {

        "CopyScalarICsRealToReal",
        "CopyScalarICsRealToComplex",
        "CopyScalarICsComplexToComplex",

        "CopyVectorICsRealToReal",
        "CopyVectorICsRealToComplex",
        "CopyVectorICsComplexToComplex",
        
        "Copy3DSampleMatrixICsRealToReal",
        "Copy3DSampleMatrixICsRealToComplex",
        "Copy3DSampleMatrixICsComplexToComplex",    

        "Copy3DFrameMatrixICsRealToReal",
        "Copy3DFrameMatrixICsRealToComplex",
        "Copy3DFrameMatrixICsComplexToComplex"    
    };

    mexPrintf("CopyICsCache info: "
        "fcn=%p, fcnIdx=%d,  (%s)\n",
         ic_cache->fcn, ic_cache->fcnIdx, mode_str[ic_cache->fcnIdx]);
}

static void displayCopyICsCache(SimStruct *S, CopyICsCache *ic_cache)
{
    displayCopyICsFcnArgs(S, &(ic_cache->args));
    displayCopyICsFcn(    S, ic_cache);
}
#endif


void initCopyICsFcn(
    SimStruct     *S,
    CopyICsCache  *ic_cache,
    const mxArray *ICs,
    int_T          dworkNum,
    int_T          portNum,
    int_T          nChans,
    int_T          fcnID
    )
{
   fillInCopyICsArgs(S, &(ic_cache->args), ICs, dworkNum, portNum, nChans);
   fillInCopyICsFcn( S, ic_cache, ICs, fcnID);

#ifdef DEBUG
   displayCopyICsCache(S, ic_cache);
#endif
}


/* [EOF] dsp_ic.c */
