RTOS Examples

The following samples for all operating systems are functionally organized in the same way. The common “driver” section illustrates the code flow for the database initialization (the main() function), the start and the commit of a real-time transaction (the realtime_job() function ) and the database access via the operating system-independent database API. The system-dependent code sections implement the timer and the callback functionality. The system-dependent timer-based approach is demonstrated for FreeRTOS, INTEGRITY OS and VxWorks, and the callback method is demonstrated for the AUTOSAR architecture and Deos. The source code is written in the C language and omits details for the sake of brevity.

The code below illustrates the operating system-independent "common sections" for the timer-based implementations.

    #ifndef MCO_REALTIME_TIMER_H
    #define MCO_REALTIME_TIMER_H
    #if defined(_LINUX) || defined (_MACOS) /* POSIX */
        #include <sys/time.h>
        typedef struct itimerval sys_timer_t;
    #endif
    void timer_handler (mco_db_h db);
    void init_sys_timer();
    void clear_sys_timer(sys_timer_t *timer);
    void set_sys_timer(sys_timer_t *timer, mco_db_h db, mco_interval_t deadline);
    #endif
			
    int realtime_job(mco_db_h db, mco_interval_t deadline)
    {
        ....
        mco_trans_rt_params_t tx_params = MCO_TRANS_DEFAULT_PARAMS;
        int n;
        set_sys_timer(&timer, db, deadline/2);

        /* Start the database transaction */
        tx_params.deadline = deadline;
        mco_trans_rt_start(db, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &tx_params, &t);
        /*
         * Continue until there is external data or the transaction is not aborted
         * either due to timeout expiration or because of some other database error.
         */
        for (n = 0; n < N_INSERTS && mco_get_last_error(t) == MCO_S_OK; ++n) {
               .....
            /* Extract data from some external source (device, network,...) and add to the 
               database */
            receive_some_data(&id, &val);
            rc = Measurement_new(t, &obj);
            if (rc == MCO_S_OK) {
                Measurement_id_put(&obj, id);
                Measurement_val_put(&obj, val);
            }
        }
        rc = mco_trans_commit(t);
        clear_sys_timer(&timer);
        return rc;
	
    int main () 
    {
        .....
        init_sys_timer(); 
        realtime_job(); 
        close_database(); 
        return 0;
    }
        

VxWorks

The following code illustrates the VxWorks implementation via the watchdog timer facility. Any task can create a watchdog timer and use it to run a specified routine in the context of the system-clock ISR, after a specified delay. The hardware timer that drives the watch dog timers generates interrupts at a programmable rate and the associated interrupt service routine scans each timer, decrements counters associated with running timers, and calls the timeout routine associated with any watchdog timers that are found to have expired.

    #include "timer_implementation.h" 

    /* system timer operations */ 
    #if defined(_VXWORKS) 
        #include "vxWorks.h" 
        #include "logLib.h" 
        #include "wdLib.h" 

        static WDOG_ID wdId; 

        void init_sys_timer() {

        /* create a watchdog */ 
        wdId = wdCreate( );
        } 

        void set_sys_timer(sys_timer_t *timer, mco_db_h db, mco_interval_t deadline) {

            /* setup a watchdog */ 
            wdStart ( wdId, sysClkRateGet( ) * deadline  , timer_handler, (int) db );
        }

        void clear_sys_timer(sys_timer_t *timer) {

            /* remove the watchdog */ 
            wdDelete( wdId ); 
    } 
    #endif

			

FreeRTOS

The FreeRTOS implementation of the control timer uses the software timers service. There is a dedicated ‘Tmr Svc‘ (Timer Service or Daemon) task which maintains an ordered list of software timers, with the timer to expire next in the front of the list. The Timer Service task is not continuously running: from the Timer List the task knows the time when it must wake up each time a timer in the timer list has expired. When a timer has expired, the Timer Service task calls its callback (the Timer callback). FreeRTOS software timers support two different types of software timers, configured when the timer is created: One-Shot timer such that when the timer expires, it is not restarted again and an Auto-Reload timer that will be automatically restarted when it expires. The sample code runs a one-shot software timer to control the deadline of the transactions. It is required, so FreeRTOS itself must be configured to support software timers (#define config USE_TIMERS 1 in FreeRTOSConfig.h) and be given enough priority to serve the events on time.


    #include <mco.h>
    #include "common.h"
    #include "timer_implementation.h"

    /* system timer operations */

    #if defined(_FREERTOS)

    #include <FreeRTOS.h>

    static mco_db_h myDB;

    void TimerProc( TimerHandle_t xTimer ) {
    timer_handler( myDB );
    }
    void init_sys_timer() {
    }

    void set_sys_timer(sys_timer_t *timer, mco_db_h db, mco_interval_t deadline)
    {
        /* Keep the reference to the current database connection */
        myDB = db;
        xTimerCreate( "eXdb-timer", pdMS_TO_TICKS(deadline), pdFALSE, TimerProc );
    }

    void clear_sys_timer(sys_timer_t *timer) {
    }
    #endif

			

INTEGRITY

The INTEGRITY OS implementation below uses PrimaryClock and Alarm to implement the control timer. A Clock is an object that allows access to a hardware timer. Clocks can be used to read the time, set the time, or set an alarm. Each Clock possesses its own alarm. This allows multiple alarms to be set on the same hardware timer. In practice, the kernel multiplexes the many alarms onto the hardware timer’s single alarm. PrimaryClock is the standard tick timer that is available on every board. This timer is run off of the scheduler tick, which normally ticks at 60 Hz. The Alarm can be set to go off either at the specified time or after the passing of a specified interval. The Alarm can be specified as repeating, in which case after the Alarm goes off another

Alarm is automatically set after a specified interval without the program explicitly setting a new Alarm. According to INTEGRITY’s message-based architecture, an Alarm is structured by the kernel like a send of an empty message on its Clock Object. This allows Alarms to be obtained either synchronously or asynchronously. An Alarm is obtained synchronously via a call to SynchronousReceive(), wherein the obtaining Task blocks until the Alarm goes off. An Alarm is obtained asynchronously via a call to AsynchronousReceive(), wherein the obtaining Task can continue about its business until the Alarm goes off, at which point the Task is notified.

The sample code utilizes a synchronous Alarm set on the PrimaryClock to implement the timer.

 


    #include <mco.h>
    #include "common.h"
    #include "timer_impl.h"

    /* system timer operations */

    #if defined(_INTEGRITY)

    #include <INTEGRITY.h>

    Clock AlarmClock;
    Task  TimerTask;
    volatile int stop_timer_task = 0;
    mco_db_h timer_connection = 0;

    static int TimerProc( Address param) {
    
        do {
    
            SynchronousReceive( (Connection)AlarmClock, NULL );
            /* Call the timer handler */
            timer_handler( * ((mco_db_h*)param) );
    
        } while (!stop_timer_task);
    
        return 0;
    }
    
    int init_sys_timer() {
    
        Error E;
        Value P;
        Value W;
        Time  res;
        Time  AI;
        timer_unit tm;
    
     E = GetClockResolution( HighestResStandardClock, &res);
        if ( E == Success ) {
            printf("Timer resolution is %.6f microsec\n", res.Seconds * 1000000.0 + res.Fraction / (0xFFFFFFFF/1000000.0)  );
        } else {
            printf("GetClockResolution() failed, %u\n", E );
        }
    
        printf("Testing mco_system_get_current_time()...\n");
        tm = mco_system_get_current_time();
        AI.Seconds  = 0;
        AI.Fraction = (0xFFFFFFFF/1000) * 123;
        E = SetClockAlarm( HighestResStandardClock, false, NULLTime, &AI );
        if ( E != Success ) {
           printf("SetClockAlarm(...) == %u\n", E);
        } else {
            E = SynchronousReceive( (Connection)HighestResStandardClock, NULL );
            if ( E != Success ) {
                printf("SynchronousReceive(...) == %u\n", E);
            }
        }
        tm = mco_system_get_current_time()-tm;
    
        printf("Sleeping for 123000 microsec took %u microsec\n", tm);
    
        E = CreateVirtualClock(HighestResStandardClock, CLOCK_READTIME|CLOCK_ALARM, &AlarmClock);
        if ( E != Success ) {
            printf("CreateVirtualClock(...) == %u\n", E);
            return 0;
        }
    
    
        /* setup the task */
        E = GetPriorityAndWeight( CurrentTask(), &P, &W );
        if ( E == Success ) {
    
            E = CommonCreateTaskWithArgument ( P, (TASKENTRYPOINT)TimerProc, (Address)&timer_connection, 1024, "eXdb-Timer", &TimerTask); /* use CommonCloseTask()*/
            if ( E != Success ) {
                printf("CommonCreateTask(...) == %u\n", E);
                return 0;
            }
    
            SetPriorityAndWeight( TimerTask, P, W, true);
    
            RunTask(TimerTask);
    
        } else {
            printf("GetPriorityAndWeight( CurrentTask(), ...) == %u\n", E);
            return 0;
        }
    
        return 1;
    
    
    }
    
    
    void shutdown_sys_timer() {
    
        Error E;
        Time  AI;
        AI.Seconds  = 0;
        AI.Fraction = 1;
    
        stop_timer_task = 1;
    
        E = SetClockAlarm( AlarmClock, false, NULLTime, &AI );
        if ( E != Success ) {
           printf("SetClockAlarm(...) == %u\n", E);
        }
    
        SynchronousReceive( (Connection)TimerTask, NULL );
        CommonCloseTask( TimerTask );
    
        CloseClock( AlarmClock );
    }
    
    
    int set_sys_timer(sys_timer_t *timer, mco_db_h db, mco_interval_t deadline) {
    
        Error E;
        Time  AI;
        Time  increment;
    
        /* Set the alarm */
        AI.Seconds  = deadline / 1000;
        AI.Fraction = (0xFFFFFFFF/1000) * (deadline % 1000);
    
        E = GetClockResolution( AlarmClock, &increment);
        if ( E != Success ) {
            printf("GetClockResolution(...) == %u\n", E);
            return 0;
        }
    
    
        if ( (increment.Seconds * 1000 + increment.Fraction / (0xFFFFFFFF/1000)) < deadline ) {
    
            timer_connection = db;
    
            E = SetClockAlarm( AlarmClock, false, NULLTime, &AI );
            if ( E != Success ) {
                printf("SetClockAlarm(...) == %u\n", E);
                return 0;
            }
        } else {
                printf("Timer resolution %.6f microsec is not enough for the deadline %u msec\n", 1000000.0 * increment.Seconds + increment.Fraction / (0xFFFFFFFF/1000000), deadline);

            return 0;
        }
    
        return 1;
    }
    
    
    void clear_sys_timer(sys_timer_t *timer) {
        Value overruns;
        Error E;
        Time  AI;
    
        AI.Seconds  = 0;
        AI.Fraction = 1;
    
        E = SetClockAlarm( AlarmClock, false, NULLTime, &AI );
        if ( E != Success ) {
           printf("SetClockAlarm(...) == %u\n", E);
        }
    
        E = ClearClockAlarmOverruns( AlarmClock, &overruns);
        if ( E != Success ) {
            printf("ClearClockAlarmOverruns(...) == %u\n", E);
        }
    }
    
    
    #endif