/*
 * Copyright (c) 1990-1999 The MathWorks, Inc. All Rights Reserved.
 * The MathWorks grants you the right to copy this file to other 
 * computer systems and embed this file within your products. You 
 * can make modifications for your application.
 *
 * File: simstruc.h     $Revision: 1.2 $
 *
 * Abstract:
 *  Data structures and access methods for sigmaps, siglists and sigregions.
 *
 *  Allows access to simulink signals.  See <matlabroot>/simulink/src/barplot.c
 *  for example code and 
 *  <matlabroot>\toolbox\simulink\simdemos\sfcndemo_barplot.mdl for an example
 *  model.  Also see the 'PUBLIC DESCRIPTION' section at the bottom of 
 *  of the file for further explanation and the list of macro assessors that
 *  should be used to access the sigmap and siglist info.  Note that direct
 *  access to these structures is not recomended as the structures may
 *  change in future releases.
 */

#ifndef sigmapdef_h
#define sigmapdef_h


#define SLREG_NO_FLAGS (0)

#define SLREG_AVAIL   (1U << 0) 
#define SLREG_REUSED  (1U << 1)
#define SLREG_FCNCALL (1U << 2)
#define SLREG_MERGE   (1U << 3)
#define SLREG_GROUND  (1U << 4) 
#define SLREG_FRAME   (1U << 5)      /* opt exclude flag-see below      */
#define SLREG_MATRIX  (1U << 6)      /* opt exclude flag-see below      */
#define SLREG_COMPLEX (1U << 7)      /* opt exclude flag-see below      */
#define SLREG_ALLOW_REUSED (1U << 8) /* opt un-exclude flag - see below */

/* region node */
typedef struct SL_SigRegion_tag {
#if !defined(S_FUNCTION_NAME)
    slPort *portObj;        /* output port associated with reg */
#else
    void *portObj;
#endif
    const void   *data;     /* pointer to the data              */
    int          startIdx;  /* starting index of the region     */
    int          nEls;      /* number of elements in region     */
    bool         entireSig; /* is this region the whole sig?    */
    unsigned int status;    /* bit field: see SLREG_xxx status
                             * vals above */

    /*
     * The following can be derived from the port, but since s-functions
     * do not currently have direct access to the internal slPort *,
     * we must put a copy of the required info directly into this struct.
     */
    int dType;
    int dTypeSize;
    int complexity;
    int m;  /* number of rows (-1 if not matrix) */
    int n;  /* number of cols (-1 if not matrix) */

    struct SL_SigRegion_tag *next;
} SL_SigRegion;

typedef struct SL_SigMap_tag {
    /* array of regions */
    int          nSigRegions; /* number of regions */
    SL_SigRegion sigRegions;  /* the regions       */

    int nEls;                /* total # els across the regions */

    bool tieWrap;   /* 
                     * If 'entireSig' == true for every region, then this is
                     * a simple grouping of complete signals. (also true if
                     * only one complete signal).
                     */
} SL_SigMap;

typedef struct SL_SigInfo_tag {
#if !defined(S_FUNCTION_NAME)
    slPort *portObj;            /* graphical port obj */
#else
    void *portObj;
#endif

    SL_SigMap *sigMap;  /* actual region map for this port */
} SL_SigInfo;

typedef struct SL_SigList_tag {  /* an array of sigInfos */
    int        nSigs;
    SL_SigInfo *sigInfos;
} SL_SigList;

/*
 * Signal selection option.
 */
#if !defined(S_FUNCTION_NAME)
typedef enum {
    SIGSET_GRAPH,            /* specified graph only */
    SIGSET_GRAPH_N_CHILDREN  /* specified graph and all child graphs */
} SigSetOpt;
#else
#define SIGSET_GRAPH            (0)
#define SIGSET_GRAPH_N_CHILDREN (1)
#endif


/*******************************************************************************
 *                  SIGLIST: PUBLIC DESCRIPTION                                *
 ******************************************************************************/

/*
 * A high-level overview of the signal list is provided here.  For more details,
 * feel free to examine the data structures defined above.  More information
 * is also provided for the individual access macros defined below.
 *
 * WARNING:
 *  DO NOT DIRECTLY ACCESS ANY OF THESE DATA STRUCTURES.  THEY MAY CHANGE
 *  IN FUTURE RELEASES.  USE THE ACCESS MACROS PROVIDED BELOW.  SEE
 *  <matlabroot>/simulink/src/barplot.c FOR A WORKING EXAMPLE OF DATA ACCESS
 *  VIA SIGNAL MAPS.
 *
 *
 * A signal list is an array of sigInfo structures:
 *  -----------------------------------
 *  | graphical port | graphical port |
 *  | signal map     | signal map     |
 *  -----------------------------------
 *
 *      graphical port:
 *          A pointer to the output port associated with a signal.  It is
 *          graphical in the sense that it may or may not map back to the
 *          actual outport from which the data originates.   Consider:
 *
 *          -----        --------
 *          | A |>------>|      |
 *          -----        |      |
 *          -----        |  C   |>---------->
 *          | B |>------>|      |
 *          -----        |------|
 *                         mux
 *
 *          For the mux block, the 'graphical' port is C.  The two 'actual'
 *          ports are A and B.
 *
 *      signal map:
 *          A linked list of contiguous regions of memory corresponding to
 *          the graphical signal.  Assuming that A and B above are 
 *          non-virtual blocks (e.g., gains, constants, etc, but not mux
 *          demux, etc), then the signal C has two contiguous regions.
 *
 *          The signal map looks like:
 *              
 *              ----------------   --> ----------------   --> NULL
 *              | region info A|   |   | region info B|   |
 *              | next region--|----   | next region--|----
 *              ----------------       ---------------- 
 *
 *          Note that if we create a signal list for A, the graphical port
 *          and the actual port are an identity mapping.  The resulting
 *          signal map consists would consist of only 1 region (assuming that
 *          the output of A is contiguous).
 *              
 *          The regions are essentially pointers into the Simulink memory areas
 *          that are used for block input and output.  Here is some of the info 
 *          contained in the regions.  Other info is also available.  See macro
 *          definitions at the bottom of this file.
 *
 *              data: a void pointer to the data in this region
 *              nEls: number of elements in region
 *              
 *              status: a flag that indicates whether or not the region is
 *                      available for access.  When regions are not available,
 *                      the 'data' field is NULL.  Status can take on the
 *                      following values:
 *                  
 *                          SLREG_AVAIL:
 *                              Data is available for access.
 *
 *                          ====================================================
 *                          The following types of regions are excluded by
 *                          default from the signal list.
 *                          ====================================================
 *
 *                          SLREG_REUSED:
 *                              The output memory area for this signal is being
 *                              shared with the output from another port.  This
 *                              signal can not be accessed (click 'Disable
 *                              optimized block I/O storage' on the Diagnostics
 *                              page of the Simulation Parameter Dialog box
 *                              to disable the sharing of block I/O memory).
 *
 *                          SLREG_FCNCALL:
 *                              The data corresponds to a fcn-call connection.
 *                              There is no data to view.
 *
 *                          SLREG_MERGE:
 *                              This signal is being merged.  This is a special
 *                               case of a buffer being re-used.  The
 *                               signal cannot be accessed.
 *
 *                          ====================================================
 *                          The following types of regions are optionally
 *                          excluded from the signal list.  See the excludeFlags
 *                          arg of ssCallSigListCreateFcn().
 *
 *                          If you are not excluding a given region type, the 
 *                          region status will be SLREG_AVAIL.  Otherwise, if
 *                          the excluded region type, SLREG_xxx, is encountered,
 *                          the region status will be SLREG_xxx.
 *                          ====================================================
 *
 *                          SLREG_FRAME:
 *                              The data region corresponds to a frame (a time
 *                              series of data points).  If your application
 *                              does not support frames, include SLREG_FRAME
 *                              as part of the excludeFlags to ensure that
 *                              all frame data is excluded from the sigList.
 *
 *                          SLREG_MATRIX:
 *                              The data region corresponds to a matrix.  If
 *                              your application does not support matrices,
 *                              include SLREG_MATRIX as part of the 
 *                              excludeFlags to ensure that all matrices are
 *                              excluded from the sigList.
 *
 *                          SLREG_COMPLEX:
 *                              The data region corresponds to complex data.  If
 *                              your application does not support complex data,
 *                              include SLREG_COMPLEX as part of the 
 *                              excludeFlags to ensure that all complex data is
 *                              excluded from the sigList.
 *
 *                          ====================================================
 *                          The following overrides the default exclusions
 *                          of the specified type of regions.
 *                          ====================================================
 *
 *                          SLREG_ALLOW_REUSED
 *                              "un-exludes" reused regions (which are excluded
 *                              by default.  As described above in the
 *                              SLREG_REUSED section, this can lead to
 *                              unexpected results, unless the block that is
 *                              requesting the signal access is hardwired into
 *                              the diagram.
 *
 *                              In general, if a block has input ports, this
 *                              flag should be specified (assuming that the 
 *                              sigmaps being created correspond to its input
 *                              ports).
 *
 *              dType:      The Simulink data type id for the data.
 *              dTypeSize:  Number of bytes in 1 non-complex element.
 *              complexity: true if the data values are complex
 *              m:          if a matrix, the number of rows (-1 if not matrix)
 *              n:          if a matrix, the number of cols (-1 if not matrix)
 *
 *
 *  In general, the following snippet of code can be used to walk the elements
 *  of a signal:
 *      SL_SigRegion *sigReg = gsl_FirstReg(sigList,i);
 *       
 *      do {
 *         int nEls = gsr_nEls(sigReg);
 *
 *          if (nEls > 0) {
 *              int        el;
 *              int        dType   = gsr_DataType(sigReg);
 *              int        elSize  = gsr_DataTypeSize(sigReg);
 *              const char *data   = gsr_data(sigReg);
 *
 *              for (el=0; el<nEls; el++) {
 *                  data += elSize;
 *              }
 *          }
 *      } while((sigReg = gsr_NextReg(sigReg)) != NULL);
 */


/*******************************************************************************
 *                  SIGLIST: PUBLIC ACCESSORS                                  *
 ******************************************************************************/

/*
 * Number of signals in the signal list.
 */
#define gsl_nSigs(sigList) ((sigList)->nSigs)

/*
 * Number of regions comprising the 'listIdx-th' signal in the list.
 */
#define gsl_nSigRegions(sigList,lstIdx) \
    (sigList->sigInfos[(lstIdx)].sigMap->nSigRegions)

/*
 * A pointer to the first region of the 'listIdx-th'signal in the list.
 */
#define gsl_FirstReg(sigList,lstIdx) \
    (&sigList->sigInfos[(lstIdx)].sigMap->sigRegions)

/*
 * The total number of elements comprising the 'listIdx-th' signal in the list.
 */
#define gsl_NumElements(sigList,lstIdx) \
    (sigList->sigInfos[(lstIdx)].sigMap->nEls)

/*
 * Returns true if the signal is a tie wrap.  This means that the signal map
 * consists of either:
 *  o one entire signal (i.e., the output of 1 non-virtual block)
 *  o a simple bundling together of multiple entire signals
 *
 *  Generally the only way to get a non-tie-wrapped signal is to mix the
 *  elements of existing signals or re-shuffle them via the use of the selector,
 *  mux and demux blocks.
 *
 *
 *      -----      -----                               --------
 *      | 1 | ---->|   |           -----               |      |
 *      -----      |   |           |   |        ------>|      |
 *     constant    |   | tie wrap  |   |------  |      |      |  not a tie wrap  
 *      -----      |   |---------->|   |     |  |      |      |--------------->
 *      | 1 | ---->|   |           |   |  ---|--|      |      | elements got 
 *      -----      |   |           |   |--|  |-------->|      |   shuffled
 *     constant    -----           |   |               |      |
 *                   mux           -----               --------
 *                                 demux                 mux
 *
 *
 */
#define gsl_TieWrap(sigList,lstIdx) \
    (sigList->sigInfos[(lstIdx)].sigMap->tieWrap)

/*
 * Get the pointer to the port associated with the 'listIdx-th' signal in the
 * list.
 */
#define gsl_PortObj(sigList,lstIdx) \
    (sigList->sigInfos[(lstIdx)].portObj)

/*
 * Get a pointer to the sigMap associated with the 'listIdx-th' signal in the
 * list.
 */
#define gsl_SigMap(sigList,lstIdx) ((sigList)->sigInfos[(lstIdx)].sigMap)

/*******************************************************************************
 *                  SIGMAP: PUBLIC ACCESSORS                                   *
 ******************************************************************************/

/*
 * A pointer to the first region of the 'listIdx-th'signal in the list.
 */
#define gsm_FirstReg(sigMap) (&((sigMap)->sigRegions))

/*******************************************************************************
 *                  SIGREGION: PUBLIC ACCESSORS                                *
 ******************************************************************************/

/*
 * The number of elements in the region.
 */
#define gsr_nEls(reg) ((reg)->nEls)

/*
 * A pointer to the next region in the linked list. NULL if at the end of
 * the list.
 */
#define gsr_NextReg(reg) ((reg)->next)

/*
 * A const char * pointer into the data.
 */
#define gsr_data(reg) ((const char *)((reg)->data))


/* 
 * The simulink data type identifier for the region.
 */
#define gsr_DataType(reg) ((reg)->dType)

/*
 * The number of bytes in one, non-complex data value.
 */
#define gsr_DataTypeSize(reg) ((reg)->dTypeSize)

/*
 * True if the data region contains complex elements.
 */
#define gsr_Complex(reg) ((reg)->complexity)

/*
 * If a matrix, the number of rows, else -1.
 */
#define gsr_M(reg) ((reg)->m)

/*
 * If a matrix, the number of cols, else -1.
 */
#define gsr_N(reg) ((reg)->n)

/*
 * The availability status of the region (SLREG_AVAIL if avail, else one
 * of the status described above in the "Public Description" section.
 */
#define gsr_status(reg) ((reg)->status)

#endif /* sigmapdef_h */
