static void task01_class00(uint16_t initCondition)

{
    for(;;)
    {
        uint16_t u;

        ++ _noLoopsTask01_C0;

        /* For test purpose only: This task consumes the CPU for about 50% of the cycle
           time. */
        delay(5 /*ms*/);

        /* Release high priority task for a single cycle. It should continue operation
           before we return from the suspend function sendEvent. Check it. */
        u = _noLoopsTask00_C1;
        rtos_sendEvent(/* eventVec */ RTOS_EVT_EVENT_00);
        ASSERT(u+1 == _noLoopsTask00_C1)

        /* Double-check that this task keep in sync with the triggered task of higher
           priority. */
        ASSERT(_noLoopsTask01_C0 == _noLoopsTask00_C1)

        /* This tasks cycles with about 10 ms. This will succeed only if the other task in
           the same priority class does not use lengthy blocking operations. */
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 10 /*ms*/);
    }
} /* End of task01_class00 */
Example #2
0
static void taskDcf(uint16_t initialResumeCondition)
{
    do
    {
        sampleAndDecodeDcfSignal();
    }
    while(rtos_suspendTaskTillTime(/* deltaTimeTillResume */ TASK_TIME_IN_TICS));

} /* End of taskDcf */
Example #3
0
static void task00_class01(uint16_t initCondition)

{
    for(;;)
    {
        ++ _noLoopsTask00_C1;

        /* This tasks cycles with about 2 ms. */
        //u = rtos_delay(255);
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 1);
    }
} /* End of task00_class01 */
Example #4
0
static void task00_class00(uint16_t initCondition)

{
    for(;;)
    {
        ++ _noLoopsTask00_C0;

        /* This tasks cycles with about 200ms but it is nearly always suspended and doesn't
           produce significant CPU load. */
        rtos_delay(80);
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 100);
    }
} /* End of task00_class00 */
Example #5
0
static void task01_class00(uint16_t initCondition)

{
    uint32_t tiCycle0 = millis();
    for(;;)
    {
        uint16_t u;
        
        ++ _noLoopsTask01_C0;

        /* The next operation (Arduino delay function) takes the demanded world time in ms
           (as opposed to CPU time) even if it is interrupted because of an elapsed round
           robin counter.
             As this task has a round robin time slice of 4 ms, the delay operation will
           surely be interrupted by the other task - which may consume the CPU for up to 20
           ms. The delay operation may thus return after 24 ms. */
        uint32_t ti0 = millis();
        delay(8 /* ms */);
        uint16_t dT = (uint16_t)(millis() - ti0);
        ASSERT(dT >= 7);
        ASSERT(dT <= 25);

        /* Release the high priority task for a single cycle. It should continue operation
           before we leave the suspend function here. Check it. */
        ti0 = millis();
        u = _noLoopsTask00_C1;
        rtos_sendEvent(/* eventVec */ RTOS_EVT_EVENT_00);
        ASSERT(u+1 == _noLoopsTask00_C1)
        ASSERT(_noLoopsTask01_C0 == _noLoopsTask00_C1)
        dT = (uint16_t)(millis() - ti0);
        ASSERT(dT <= 2);
        
        /* The body of this task takes up to about 26 ms (see before). If it suspends here,
           the other round robin task will most often become active and consume the CPU the
           next 20 ms. This tasks wants to cycle with 40 ms. So it'll become due while the
           other round robin task is active. This task will become active only after the
           time slice of the other task has elapsed. Exact cycle time is impossible for
           this task.
             It can even be worse if the other round robin task should be suspendend while
           this task suspends itself till the next multiple of 40 ms: Occasionally, the
           other task will resume just before this task and the activation of this task
           will be delayed by the full time slice duration of the other round robin task.
           Task overruns are unavoidable for this (ir-)regular task, but we can give an
           upper boundary for the cycle time, which is tested by assertion. */
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 20 /* unit 2 ms */);
        uint32_t tiCycleEnd = millis();
        dT = (uint16_t)(tiCycleEnd - tiCycle0);
        tiCycle0 = tiCycleEnd;
        ASSERT(dT <= 62);
    }
} /* End of task01_class00 */
Example #6
0
static void taskRTC(uint16_t initialResumeCondition)
{
    ASSERT(initialResumeCondition == RTOS_EVT_ABSOLUTE_TIMER);

    /* Regularly call the RTC implementation at its expected rate: The RTC module exports the
       expected task time by a define. */
    do
    {
        clk_taskRTC();
    }
    while(rtos_suspendTaskTillTime
                    (/* deltaTimeTillResume */ CLK_TASK_TIME_RTUINOS_STANDARD_TICS)
         );
    ASSERT(false);

} /* End of taskRTC */
Example #7
0
static void task01_class00(uint16_t initCondition)

{
#define TICS_CYCLE  125

    uint16_t u;
    uint32_t ti = millis()
           , tiCycle;
    
    Serial.print("task01_class00: Activated by 0x");
    Serial.println(initCondition, HEX);

    for(u=0; u<3; ++u)
        blink(2);
    
    for(;;)
    {
        Serial.println("task01_class00: rtos_delay...");
        u = rtos_delay(55);
        Serial.print("task01_class00: Released with ");
        Serial.println(u, HEX);
        
        Serial.println("task01_class00: Suspending...");
        u = rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ TICS_CYCLE);
        tiCycle = millis();
        Serial.print("task01_class00: Released with ");
        Serial.println(u, HEX);
        
        /* The system timer tic has a frequency of 490.1961 Hz.
             Caution: The compiler fails to recognize the constant floating point
           expression if there's no explicit, superfluous pair of parenthesis around it.
           With parenthesis it compiles just one product, without it uses several products
           and divisions. */
        Serial.print("Cycle time: ");
        Serial.print((tiCycle-ti) * (100.0/1000.0 / (TICS_CYCLE/490.1961)));
        Serial.println("%");
        
        Serial.print("CPU load: ");
        Serial.print(_cpuLoad/2);
        Serial.println("%");
        
        ti = tiCycle;
    }
    
#undef TICS_CYCLE
} /* End of task01_class00 */
Example #8
0
static void taskT0_C1(uint16_t initCondition)
{
#define TASK_TIME_T0_C1_MS  21

    uint32_t cnt = 0;
    
    /* The task inspects the results of the interrupt on a regular base. */
    do
    {
        /* Wait until we get the resource. */
        getResource();
    
        /* Being here, we can be sure to have the resource. Use it. */
        
        /* The ownership of the resource needs to be independent of the status of the
           tasks. To prove this we suspend the task deliberately in the middle of some
           output operation and we use the blocking Arduino function delay that long, that
           we have a high probability of running into a round robin task switch before
           delay returned. */
        Serial.print("This is task T0_C1");
        Serial.print(": "); Serial.print(++cnt);
        Serial.print(" loops. This line of conso");
        rtos_delay(TIME_IN_MS(7));
        Serial.print("le output is interr");
        delay(3/*ms*/);
        Serial.print("upted by several task de-activations");
        Serial.println(". Now the resource is released again");

        /* Give other tasks a chance to get the resource. */
        releaseResource();
        
        /* Here, no other task will already use the acquired resource: All concurrent tasks
           are of lower priority. One of them will have become due but not active yet. The
           while condition will now make this task inactive and the already due other one
           active. */
    }
    while(rtos_suspendTaskTillTime(TIME_IN_MS(TASK_TIME_T0_C1_MS)));

#undef TASK_TIME_T0_C1_MS
} /* End of taskT0_C1 */
Example #9
0
static void task01_class00(uint16_t initCondition)

{
    for(;;)
    {
        ++ _noLoopsTask01_C0;

        /* For test purpose only: This task consumes the CPU for most of the cycle time and
           while the task is active. The call of delay produces a CPU load of about 80%.
           This is less self-explaining as it looks on the first glance. The Arduino
           function delay is implemented as loop, which compares the current system time
           with a target time, the desired time of return. The current system time is
           clocked by an interrupt independent of RTuinOS. This loop will basically run
           during 80 ms in a cycle of about 100 ms - but not continuously. The task of
           higher priority will frequently interrupt and shortly halt the loop. Therefore
           the 80% of CPU load do not result from this task (as it may seem) but from this
           task and all others which may interrupt it while it is looping inside delay. */
        delay(80 /*ms*/);
        
        /* This tasks cycles with about 100ms. */
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 50);
    }
} /* End of task01_class00 */
static void task00_class00(uint16_t initCondition)

{
    uint32_t ti1, ti2=0;

    for(;;)
    {
        ++ _noLoopsTask00_C0;

        /* To see the stack reserve computation working we invoke a nested sub-routine
           after a while. */
        if(millis() > 20000ul)
            subRoutine(1);
        if(millis() > 30000ul)
            subRoutine(2);
        if(millis() > 40000ul)
            subRoutine(3);

        /* Wait for an event from the idle task. The idle task is asynchrounous and its
           speed depends on the system load. The behavior is thus not perfectly
           predictable. */
        if(rtos_waitForEvent( /* eventMask */ RTOS_EVT_EVENT_03 | RTOS_EVT_DELAY_TIMER
                            , /* all */ false
                            , /* timeout */ 200 /*ms*/
                            )
           == RTOS_EVT_DELAY_TIMER
          )
        {
            ++ _task00_C0_cntWaitTimeout;
        }

        /* This tasks cycles with the lowest frequency, once per system timer cycle.
            CAUTION: Normally, this is not permitted. If the suspend time is more than
           half the range of the data type chosen for its system time RTuinOS is no longer
           capable to safely recognize task overruns. False recognitions would lead to bad
           task timing as the corrective action is to make the (only seemingly) late task
           due immediately. */
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 0);

        /* A task period of more than half the system timer cycle leads to a high
           probability of seeing task overruns where no such overruns happen. (See RTuinOS
           manual.)
             We therefore disable the standard corrective action in case of overruns; macro
           RTOS_OVERRUN_TASK_IS_IMMEDIATELY_DUE is set to RTOS_FEATURE_OFF.
             The false overruns are counted nonetheless by rtos_getTaskOverrunCounter.
           Here, we implement our own overrun counter by comparing the task cycle time with
           the Arduino timer which coexists with the RTuinOS system timer. */
        ti1 = millis();
        if(ti2 > 0)
        {
            ti2 = ti1-ti2;
            if(ti2 < (uint32_t)(0.9*256.0*RTOS_TIC*1000.0)
               ||  ti2 > (uint32_t)(1.1*256.0*RTOS_TIC*1000.0)
              )
            {
                ++ _task00_C0_trueTaskOverrunCnt;
            }
        }
        ti2 = ti1;

        /* What looks like CPU consuming floating point operations actually is a
           compile time operation. Here's the prove - which also produces no CPU load
           as it is removed by the optimizer. (Sounds contradictory but it isn't.) */
        ASSERT(__builtin_constant_p((uint32_t)(0.9*256.0*RTOS_TIC*1000.0))
               &&  __builtin_constant_p((uint32_t)(1.1*256.0*RTOS_TIC*1000.0))
              );

    } /* End for(ever) */

} /* End of task00_class00 */