⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mrt_sim.c

📁 simulink real-time workshop for dragon12 development board from
💻 C
字号:
/* Copyright 1994-2002 The MathWorks, Inc.
 *
 * File    : mrt_sim.c     $Revision: 1.10 $
 * Abstract:
 *   Performs one time step of a real-time single tasking or multitasking
 *   system when timing data is dynamically allocated.
 */


/*==========*
 * Struct's *
 *==========*/

/*
 * TimingData
 */
typedef struct TimingData_Tag {
    real_T *period;       /* Task periods in seconds                   */
    real_T *offset;       /* Task offsets in seconds                   */
    real_T *clockTick;    /* Flint task time tick counter              */
    int_T  *taskTick;     /* Counter for determining task hits         */
    int_T  *nTaskTicks;   /* Number base rate ticks for a task hit     */
    int_T  firstDiscIdx;  /* First discrete task index                 */
} TimingData;

/*==================*
 * Visible routines *
 *==================*/

/* Function: rt_SimInitTimingEngine ============================================
 * Abstract:
 *      This function is for use with single tasking or multitasking
 *      real-time systems.  
 *
 *      Initializes the timing engine for a fixed-step real-time system. 
 *      It is assumed that start time is 0.0.
 *
 * Returns:
 *      NULL     - success
 *      non-NULL - error string
 */
const char *rt_SimInitTimingEngine(int_T       rtmNumSampTimes,
                                   real_T      rtmStepSize,
                                   real_T      *rtmSampleTimePtr,
                                   real_T      *rtmOffsetTimePtr,
                                   int_T       *rtmSampleHitPtr,
                                   int_T       *rtmSampleTimeTaskIDPtr,
                                   real_T      rtmTStart,
                                   SimTimeStep *rtmSimTimeStepPtr,
                                   void        **rtmTimingDataPtr)
{
    int_T  i;
    int_T  *tsMap     = rtmSampleTimeTaskIDPtr;
    real_T stepSize   = rtmStepSize;
    int_T  *sampleHit = rtmSampleHitPtr;
    int_T  numst      = rtmNumSampTimes;
    real_T *period    = rtmSampleTimePtr;
    real_T *offset    = rtmOffsetTimePtr;

    TimingData *td;
    static const char_T *malloc_error = "Memory allocation error";

    td = (TimingData *) malloc(sizeof(TimingData));
    if (!td) {
        return(malloc_error);
    }

    td->period = (real_T *) malloc(numst * sizeof(real_T));
    if (!td->period) {
        return(malloc_error);
    }

    td->offset = (real_T *) malloc(numst * sizeof(real_T));
    if (!td->offset) {
        return(malloc_error);
    }

    td->clockTick = (real_T *) malloc(numst * sizeof(real_T));
    if (!td->clockTick) {
        return(malloc_error);
    }

    td->taskTick = (int_T *) malloc(numst * sizeof(int_T));
    if (!td->taskTick) {
        return(malloc_error);
    }

    td->nTaskTicks = (int_T *) malloc(numst * sizeof(int_T));
    if (!td->nTaskTicks) {
        return(malloc_error);
    }

    if (rtmTStart != 0.0) {
        return("Start time must be zero for real-time systems");
    }

    *rtmSimTimeStepPtr = MAJOR_TIME_STEP;

    *rtmTimingDataPtr = (void*)td;

    for (i = 0; i < rtmNumSampTimes; i++) {
        tsMap[i]          = i;
        td->period[i]     = period[i];
        td->offset[i]     = offset[i];
        td->nTaskTicks[i] = (int_T)floor(period[i]/stepSize + 0.5);
        if (td->period[i] == CONTINUOUS_SAMPLE_TIME ||
            td->offset[i] == 0.0) {
            td->taskTick[i]  = 0;
            td->clockTick[i] = 0.0;
            sampleHit[i]     = 1;
        } else {
            td->taskTick[i]  = (int_T)floor((td->period[i]-td->offset[i]) /
                                            stepSize+0.5);
            td->clockTick[i] = -1.0;
            sampleHit[i]     = 0;
        }
    }

    /* Correct first sample time if continuous task */
    td->period[0]     = stepSize;
    td->nTaskTicks[0] = 1; 

    /* Set first discrete task index */
    if(rtmNumSampTimes == 1) {    
        td->firstDiscIdx = (int_T)(period[0] == CONTINUOUS_SAMPLE_TIME);
    } else {
        td->firstDiscIdx = ((int_T)(period[0] == CONTINUOUS_SAMPLE_TIME) + 
                           (int_T)(period[1] == CONTINUOUS_SAMPLE_TIME));
    }

    return(NULL); /* success */

} /* end rt_SimInitTimingEngine */


/* Function: rt_SimDestroyTimingEngine ===========================================
 * Abstract:
 *      This function frees the timing engine data.
 */
void rt_SimDestroyTimingEngine(void *rtmTimingData)
{
    TimingData *td = (TimingData *)rtmTimingData;
    
    if (td) {
        if (td->period) {
            free(td->period);
        }
        
        if (td->offset) {
            free(td->offset);
        }
        
        if (td->clockTick) {
            free(td->clockTick);
        }
        
        if (td->taskTick) {
            free(td->taskTick);
        }
        
        if (td->nTaskTicks) {
            free(td->nTaskTicks);
        }
        free(td);
    }

} /* end rt_SimDestroyTimingEngine */


#if !defined(MULTITASKING)

/*###########################################################################*/
/*########################### SINGLE TASKING ################################*/
/*###########################################################################*/

/* Function: rt_SimGetNextSampleHit ==============================================
 * Abstract:
 *      For a single tasking real-time system, return time of next sample hit.
 */
time_T rt_SimGetNextSampleHit(void   *rtmTimingData,
                              int_T rtmNumSampTimes)
{
    TimingData *td           = (TimingData *)rtmTimingData;
    time_T     timeOfNextHit;

    td->clockTick[0]++;

    timeOfNextHit = td->clockTick[0] * td->period[0];

    if(rtmNumSampTimes > 1) {
        int i;
        for (i = 1; i < rtmNumSampTimes; i++) {
            if (++td->taskTick[i] == td->nTaskTicks[i]) {
                td->taskTick[i] = 0;
                td->clockTick[i]++;
            }
        }
    }

    return(timeOfNextHit);

} /* end rt_SimGetNextSampleHit */



/* Function: rt_SimUpdateDiscreteTaskSampleHits ==================================
 * Abstract:
 *      This function is for use with single tasking real-time systems.  
 *      
 *      If the number of sample times is greater than one, then we need to 
 *      update the discrete task sample hits for the next time step. Note, 
 *      task 0 always has a hit since it's sample time is the fundamental 
 *      sample time.
 */
void rt_SimUpdateDiscreteTaskSampleHits(int_T  rtmNumSampTimes,
                                        void   *rtmTimingData,
                                        int_T  *rtmSampleHitPtr,
                                        real_T *rtmTPtr)
{
    int_T      *sampleHit = rtmSampleHitPtr;
    TimingData *td        = (TimingData *)rtmTimingData;
    int        i;

    for (i = td->firstDiscIdx; i < rtmNumSampTimes; i++) {
        int_T hit = (td->taskTick[i] == 0);
        if (hit) {
            rttiSetTaskTime(rtmTPtr, i,
                            td->clockTick[i]*td->period[i] + td->offset[i]);
        }
        sampleHit[i] = hit;
    }
} /* rt_SimUpdateDiscreteTaskSampleHits */



#else /* defined(MULTITASKING) */

/*###########################################################################*/
/*############################## MULTITASKING ###############################*/
/*###########################################################################*/


/* Function: rt_SimUpdateDiscreteEvents ==========================================
 * Abstract:
 *      This function is for use with multitasking real-time systems. 
 *
 *      This function updates the status of the SimStruct mdlInfo sampleHits
 *      flags and the perTaskSampleHits matrix which is used to determine 
 *      when special sample hits occur.
 *
 *      The SimStruct mdlInfo contains a matrix, called perTaskSampleHits. 
 *      This matrix is used by the ssIsSpecialSampleHit macro. The row and 
 *      column indices are both task id's (equivalent to the root SimStruct 
 *      sample time indices). This is a upper triangle matrix. This routine 
 *      only updates the slower task hits (kept in column j) for row
 *      i if we have a sample hit in row i.
 *
 *                       column j
 *           tid   0   1   2   3   4   5  
 *               -------------------------
 *             0 |   | X | X | X | X | X |
 *         r     -------------------------
 *         o   1 |   |   | X | X | X | X |      This matrix(i,j) answers:
 *         w     -------------------------      If we are in task i, does
 *             2 |   |   |   | X | X | X |      slower task j have a hit now?
 *         i     -------------------------
 *             3 |   |   |   |   | X | X |
 *               -------------------------
 *             4 |   |   |   |   |   | X |      X = 0 or 1
 *               -------------------------
 *             5 |   |   |   |   |   |   |
 *               -------------------------
 *
 *      How macros index this matrix:
 *
 *          ssSetSampleHitInTask(S, j, i, X)   => matrix(i,j) = X
 *
 *          ssIsSpecialSampleHit(S, my_sti, promoted_sti, tid) => 
 *              (tid_for(promoted_sti) == tid && !minor_time_step &&
 *               matrix(tid,tid_for(my_sti)) 
 *              )
 *
 *            my_sti       = My (the block's) original sample time index.
 *            promoted_sti = The block's promoted sample time index resulting
 *                           from a transition via a ZOH from a fast to a 
 *                           slow block or a transition via a unit delay from 
 *                           a slow to a fast block.
 *
 *      The perTaskSampleHits array, of dimension n*n, is accessed using 
 *      perTaskSampleHits[j + i*n] where n is the total number of sample
 *      times, 0 <= i < n, and 0 <= j < n.  The C language stores arrays in 
 *      row-major order, that is, row 0 followed by row 1, etc.
 * 
 */
time_T rt_SimUpdateDiscreteEvents(int_T  rtmNumSampTimes,
                                  void   *rtmTimingData,
                                  int_T  *rtmSampleHitPtr,
                                  int_T  *rtmPerTaskSampleHits)
{
    int        i, j;
    int_T      *sampleHit = rtmSampleHitPtr;
    TimingData *td        = (TimingData *)rtmTimingData;

    /*
     * Run this loop in reverse so that we do lower priority events first.
     */
    i = rtmNumSampTimes;
    while (--i >= 0) {
        if (td->taskTick[i] == 0) {
            /* 
             * Got a sample hit, reset the counter, and update the clock
             * tick counter.
             */
            sampleHit[i] = 1;
            td->clockTick[i]++;

            /*
             * Record the state of all "slower" events 
             */
            for (j = i + 1; j < rtmNumSampTimes; j++) {
                rttiSetSampleHitInTask(rtmPerTaskSampleHits,rtmNumSampTimes,
                                       j, i, sampleHit[j]);
            }
        } else {
            /*
             * no sample hit, increment the counter 
             */
            sampleHit[i] = 0;
        }

        if(++td->taskTick[i] == td->nTaskTicks[i]){ /* update for next time */
            td->taskTick[i] = 0;
        }
    }

    return(td->clockTick[0]*td->period[0]);
    
} /* rt_SimUpdateDiscreteEvents */



/* Function: rt_SimUpdateDiscreteTaskTime ========================================
 * Abstract:
 *      This function is for use with multitasking systems. 
 *
 *      After a discrete task output and update has been performed, this 
 *      function must be called to update the discrete task time for next 
 *      time around.
 */
void rt_SimUpdateDiscreteTaskTime(real_T *rtmTPtr,
                                  void   *rtmTimingData,
                                  int    tid)
{
    TimingData *td = (TimingData *)rtmTimingData;
    rttiSetTaskTime(rtmTPtr, tid,
                    td->clockTick[tid]*td->period[tid] + td->offset[tid]);
}

#endif /* MULTITASKING */

/* EOF: mrt_sim.c */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -