ERIKA3 OIL specification

From ERIKA WIKI
Jump to: navigation, search

Introduction

The ERIKA3 RTOS is configured by means of an OIL file. The OIL file contains all information needed to configure the kernel, and in addition contains information for building the kernel library and application (this part is used in the standard eclipse distribution provided with ERIKA3.

The OIL file is written using the OIL (OSEK Implementation Language) language. The OIL language is a part of the OSEK/VDX standard. The specification of the OIL file structure and syntax was provided in the OSEK/VDX web site, and is now standardized as ISO 17356-6.

In this chapter we only provide a quick introduction of the OIL Language, together with a specification of the specific OIL attributes implemented by RT-Druid 3.

Standard OIL has no knowledge of multiprocessor systems. for this reason, Erika3 provides a set of OIL extensions that enable the user to create a multi-core configuration.

OIL Basics

In Erika3 all the RTOS objects like tasks, alarms, resources, are static and predefined at application compile time. To specify which objects exist in a particular application, Erika3 uses the OIL Language, which is a simple text description language.

Here is an example of an OIL File for the Arduino uno board:

CPU mySystem {
  OS myOs {
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
    EE_OPT = "OS_EE_BUILD_DEBUG";
    CPU_DATA = AVR8 {
      MULTI_STACK = TRUE;
      IDLEHOOK = TRUE {
        HOOKNAME = "idle_hook";
      };
    };
    MCU_DATA = MEGA {
      MODEL = MEGA_328p;
    };
    LIB = ARDUINO {
      /* Used to select Board: UNO or NANO */
      SDK_BOARD = UNO;
      /* Used to select vendor: CC or ORG */
      VARIANT = CC {
        VERSION = "1.8.5";
      };
      /* Create libarduino.a */
      STAND_ALONE = TRUE;
    };
    KERNEL_TYPE = OSEK {
      CLASS = BCC1;
    };
  };
  APPDATA myApp {
    APP_SRC  = "code.cpp";
    APP_SRC  = "task.c";
  };
  TASK TaskL1 {
    PRIORITY = 1;
    STACK = PRIVATE {
      SIZE = 128;
    };
  };
};

The example contains a single object called CPU, which contains all the objects and values used for configuring the system. The CPU object contains other objects, such as: the OS, which specifies the global attributes for the system, and, in the example, one TASK.

The OIL File is parsed by the RT-Druid code generator and, as a result, part of the RTOS source code is generated and compiled together with the application. An OIL file consists of two parts: a set of definitions and a set of declarations:

  • Definitions are used to define data types, constants and kernel objects that need to be provided in the declaration part for configuring a specific kernel. In other words, the definition part tells the configurator that there exists different objects like tasks, resources, and so on, describing their attributes and types, like in a C struct declaration.
    • In RT-Druid 3, the definition part of the OIL file is fixed and is contained inside the RT-Druid Eclipse Plugins.
  • Declarations are used to specify which objects are really present in a particular application. You can think this part as a C variable definition, which defines the object really present in a kernel configuration.
    • The user has only to provide the declaration part, specifying for a particular application the objects to be created.

The OIL file basically contains the description of a set of objects. A CPU is a container of these objects. Other objects include the following:

  • OS is the Operating System which runs on the CPU. This object contains all the global settings which influence the compilation process and the customization of the Erika3 RTOS.
  • APPDATA contains the application makefile configuration (currently, the list of files to be compiled).
  • APPMODE defines the different application mode. These modes are then used to control the autostart feature for tasks and alarms in the OIL file.
  • TASK is an application task handled by the OS.
  • RESOURCE is a resource (basically a binary mutex) used for mutual exclusion.
  • EVENT is a synchronization flag used by extended tasks.
  • COUNTER is a software source for periodic / one shot alarms.
  • ALARM is a notification mechanism attached to a counter which can be used to activate a task, set an event, or call a function.

All the attributes in the OIL file can be:

  • numbers, i.e. the PRIORITY attribute;
  • strings, i.e. the APP_SRC attribute;
  • enumerations, i.e. the KERNEL_TYPE attribute.

Attributes can have a default value, as well as an automatic value specified with the keyword AUTO. Some of the attributes can be specified more than once in the OIL file, such as the APP_SRC, and the configurator treats them as a set of values; i.e., in the case of APP_SRC, the set of application files to be compiled.

Some items can contain a set of sub-attributes, like in a C-language struct definition. For example, CPU_DATA contains a AVR8 object, which is furthermore detailed by a set of attributes.

An OIL file can be splitted in various parts. The only requirement is that the separate declarations do not contain any conflicting assignment to the same field name. As an example, The following OIL File:

CPU mySystem {
  OS myOs {
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
    EE_OPT = "OS_EE_BUILD_DEBUG";
  };
};

can be rewritten as this one:

CPU mySystem {
  OS myOs {
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
  };
  OS myOs {
    EE_OPT = "OS_EE_BUILD_DEBUG";
  };
};

The CPU Object

The CPU object is only used as a container of all the other objects, and does not have any specific attribute.

The OS Object

The OS Object is used to define the Erika3 global configuration as well as the compilation parameters. The attributes which can be specified for the OS object are specified in the following subsections.

Compilation attributes

The OIL file includes a set of fields for controlling the command line parameters which are passed to the compiler tools. The meaning of those elements is the following:

  • EE_OPT contains a list of additional compilation flags passed to the Erika3 makefile. In practice, the EE_OPT makefile variable controls which files has to be compiled and with which options. The EE_OPT attributes are translated in #defines in the application C code.
  • CFLAGS contains the list of additional C compiler options.
  • ASFLAGS contains the list of additional assembly options.
  • LDFLAGS Contains the list of additional linker parameters.
  • LDDEPS Contains the list of additional library dependencies which have to be added to the makefile rules.
  • LIBS Contains the list of additional libraries that needs to be linked.

Example of declaration:

CPU mySystem {
  OS myOs {
    EEOPT = "MYFLAG1";
    EEOPT = "MYFLAG2";
    CFLAGS = "-G0";
    CFLAGS = "-O0 -g";
    CFLAGS = "- Wall -Wl ,-Map -Wl , project .map ";
    ASFLAGS = "-g";
    LIBS = "-lm ";
    ...
  };
  ...
};

OSEK/VDX Attributes

The OIL file includes a set of attributes which are part of the OSEK/VDX specification. The meaning of those attributes is the following:

  • STATUS specifies if the kernel should be compiled with STANDARD status or EXTENDED status.
    • With the STANDARD status, only a subset of the error codes are reported by the kernel primitives to reduce the system footprint.
    • The settings STARTUPHOOK, ERRORHOOK, SHUTDOWNHOOK, PRETASKHOOK, POSTTASKHOOK specify which particular hook routine should be included in the kernel.
    • USEGETSERVICEID specifies if the Service ID debugging functionality of the ErrorHook routine should be included in the kernel.
    • USEPARAMETERACCESS specifies if the ErrorHook should have access to the parameters passed to the primitives.
    • USERESSCHEDULER specifies if the kernel includes the RES_SCHEDULER resource.

Example of declaration:

CPU mySystem {
  OS myOs {
    STATUS = STANDARD ;
    STARTUPHOOK = TRUE;
    ERRORHOOK = TRUE;
    SHUTDOWNHOOK = TRUE;
    PRETASKHOOK = FALSE;
    POSTTASKHOOK = FALSE;
    USEGETSERVICEID = FALSE;
    USEPARAMETERACCESS = FALSE;
    USERESSCHEDULER = TRUE;
    ...
  };
  ...
};

CPU_DATA sections

The CPU_DATA section of the OS object is used to specify the configuration of a core in a single or in a multiple core device. In general, the OIL file will contain a CPU_DATA section for each core in the system.

There is a specific CPU_DATA section for each architecture supported by Erika3, and each specific architecture has its own specific set of attributes. These attributes can be general attributes, which have the same meaning in all architectures, or custom attributes, which are used to configure specific architectural aspects.

  • Please check the ERIKA3 supported Architectures for a list of supported architecture. Each supported architecture has its own section with a description of the CPU_DATA custom attributes.

The general attributes of the CPU_DATA section are the following:

  • ID is a number uniquely identifying the CPU.
    • The number must be specified following the AUTOSAR conventions, that is CPUs must be numbered starting from 0.
      • CPU Numbers are not reordered like task priorities. If you specify a CPU with ID 0 and a CPU with ID 2 inside an OIL file, then CPU 1 will not be used.
      • CPU 0 is the master and must be always be configured
    • The number used for the CPU_ID attribute (in TASKs, ...) must be one of the numbers of an existing CPU.
    • CPUs with no ID automatically get a default ID of 0. If more than one CPU gets an ID 0, an error is raised.
    • ID 0 is subsumed also when allocating Tasks (ref), and counters to a CPU (ref).
    • For single processor systems, it is safe to avoid any declaration of the CPU_ID field in the entire OIL file. In this way, all the objects will be mapped to the only CPU in the system, with ID 0.
    • Example of declaration:
CPU mySystem {
  OS myOs {
    CPU_DATA = TRICORE {
      ID = 0;
      ...
    }
    ...
  };
  ...
};
  • MULTI_STACK defines if the system supports multiple stacks for the application tasks (TRUE) or not (FALSE).
    • The default value is FALSE. If set to TRUE, it is possible to specify whether IRQs are executed using a dedicated stack space. The attribute IRQ_STACK is used for this purpose.
    • Some architectures also allow the specification of a DUMMY_STACK, which specifies if the background task is using a shared stack (SHARED value) or a dedicated stack segment (PRIVATE value). ERIKA3 schedules the main() function as a background task, also called “dummy” task.
  • IDLEHOOK defines whether a Hook will be called when running the background task.
    • The name of the hook is provided under the attribute HOOKNAME.
    • The hook name must be a valid C function without input or output parameters (void hook(void)).
  • COMPILER defines which is the compiler used for the specific entry. In case of a multicore system, teh compiler must be specified the same for each CPU_DATA. Each architecture has a set of supported compilers which is specified in the per architecture wiki page.
  • PLATFORM, when present, defines which is the execution environment (it is typically specified in the cases when an hypervisor is supported). Typical values are JAILHOUSE, VIBRANTE.

Here is an example of a declaration of an Arduino Uno CPU_DATA:

CPU mySystem {
  OS myOs {
    CPU_DATA = AVR8 {
      MULTI_STACK = TRUE;
      IDLEHOOK = TRUE {
        HOOKNAME = "idle_hook";
      };
    };
  };
};

MCU_DATA section

The MCU_DATA section of the OS object is used to specify the configuration of peripherals which are present in a specific microcontroller.

  • Please check the ERIKA3 supported Architectures for a list of supported architecture. Each supported architecture has its own section with a description of the MCU_DATA custom attributes.

BOARD_DATA section

The BOARD_DATA section of the OS object is used to specify the configuration of the board where the microcontroller is placed. For example, the board configuration includes the configuration of the external devices like LEDs, buttons, displays, and other peripherals.

The default value for the BOARD_DATA section is NO_BOARD.

LIB section

The LIB section is used to configure external libraries (typically provided by silicon vendors, or other libraries) which are installed in your machine. As a result of the compilation process, these libraries are compiled and placed inside the erika/lib directory inside the Eclipse workspace.

The specification of the libraries is architecture dependent.

Example:

CPU myCPU {
  OS myOs {
    LIB = ARDUINO {
      SDK_BOARD = UNO;
      VARIANT = CC {
        VERSION = "1.8.5";
      };
      STAND_ALONE = TRUE;
    };
  };
};

Kernel Conformance Classes

An explicit declaration of the kernel conformance class is required in the KERNEL_TYPE attribute. The possible options are the following:

  • OSEK is used to specify that the kernel will be configured following one of the OSEK/VDX Conformance Classes.
    • As a sub-attribute CLASS, it is possible to specify one of the four conformance classes (BCC1, BCC2, ECC1, ECC2 (the default))
    • As a sub-attribute RQ (Ready Queue), it is possible to specify whether to use a LL Linked List (O(N) complexity, default), or a MQ Multiple Queue (O(1) complexity)
    • MQ has an additional internal parameter named PRIORITIES which is used only when the dynamic API is configured (ref), to specify the number of priorities that should be reserved in the data structure.

Here is an example of a kernel type declaration:

CPU mySystem {
  OS myOs {
    KERNEL_TYPE = OSEK {
      CLASS = ECC1;
      RQ = MQ;
    };
  };
};

ORTI File Generation

ERIKA3 provides a boolean attribute USEORTI that enables the generation of the ORTI File when set to TRUE.

  • ORTI is a standard for Kernel Awareness defined by the OSEK/VDX consortium and further extended by debugger producers with SMP extensions
  • the ORTI file generated is named out/system.orti
  • ERIKA3 supports the ORTI integration with Lauterbach TRACE32 and iSystem winIDEA

Here is an example of an ORTI file confuguration:

CPU mySystem {
  OS myOs {
    USEORTI = TRUE;
  };
};

The APPDATA Object

The APPDATA Object is used to specify build-dependent configurations.

Currently, this object holds the list of application files to be compiled to create the application binary. Basically, each file needs to be listed with an APP_SRC directive.

Example:

CPU mySystem {
  APPDATA myApp {
    APP_SRC  = "code.c";
    APP_SRC  = "hal.c";
  };
};

The Application Mode Object

The APPMODE object is contained by the CPU object and is used to define an application mode. Application modes are defined statically, and initialized inside the StartOS primitive.

Example:

CPU test_application {
  ...
  APPMODE myAppMode1;
  APPMODE myAppMode2;
  APPMODE myAppMode3;
  ...
}

The Task object

The TASK object is contained inside the CPU object and it is used to specify the properties of a task.

CPU_ID attribute

The CPU_ID attribute is a number specifying the CPU where the task has been (statically) partitioned.

  • The default value is 0
  • This attribute is only needed on Multicore systems

Example

CPU test_application {
  ...
  TASK TaskMaster {
    CPU_ID = 0x0;
    ...
  };
};


Autostart attribute

The AUTOSTART attribute specifies if the task should be automatically activated at system startup by the StartOS primitive.

  • If the task must be activated at startup, the AUTOSTART attribute has a value TRUE.
  • When TRUE, the APPMODE sub-attribute lists the application modes for which the task is autostarted.

Example:

CPU test_application {
  ...
  TASK myTask1 {
    AUTOSTART = TRUE { APPMODE = myAppMode1; };
    ...
  };
  TASK myTask2 {
    AUTOSTART = FALSE ;
    ...
  };
  ...
};

Priority attribute

The PRIORITY attribute specifies the task priority.

  • The value is used by RT-Druid as a relative ordering of priorities and not as an absolute priority value.
  • Higher values correspond to higher priorities.

Example:

CPU test_application {
  ...
  TASK myTask1 {
    PRIORITY = 1;
    ...
  };
  ...
};


Activation attribute

The ACTIVATION attribute specifies the number of pending activations which can be stored by a task.

  • If a task is activated too much, activations are lost and an error is returned by the ActivateTask / ChainTask primitive

Example:

CPU test_application {
  ...
  TASK myTask1 {
    ACTIVATION = 3;
    ...
  };
  ...
};


Schedule attribute

The SCHEDULE attribute specifies if a task is full preemptive (FULL) or non preemptive (NON). The default is NON.

Example:

CPU test_application {
  ...
  TASK myTask1 {
    SCHEDULE = FULL;
    ...
  };
  TASK myTask2 {
    SCHEDULE = NON ;
    ...
  };
  ...
};


Event attribute

The EVENT attribute is used to list the Events which belong to a task. It is used in conformance classes ECC1 and ECC2.

Example:

CPU test_application {
  ...
  TASK myTask1 {
    EVENT = "TimerEvent";
    EVENT = "ButtonEvent";
    ...
  };
  ...
};

Resource attribute

The RESOURCE attribute is used to list the Resources used by a task.

Example:

CPU test_application {
  ...
  TASK myTask1 {
    RESOURCE = "Resource1";
    RESOURCE = "Resource2";
    ...
  };
  ...
};

Stack attribute

The STACK attribute is used to specify if the task stack is shared or of the task should have a separate private stack.

  • A private stack is needed when the task calls one of the available blocking primitives (currently, WaitEvent, and WaitSem)
    • Please note that these blocking primitives needs a separate stack in order to work correctly. For this reason, these primitives can check at runtime whether the task calling them has a separate stack.
    • For implementation reasons, the check on the fact that a task has a separate stack is done by checking whether the task is an extended task.
      • A task using events is by definition an extended task
      • A task using semaphores needs to explicitly specify the fact that it is an extended task. This is done by marking EXTENDED = TRUE inside its PRIVATE stack.

Example:

CPU test_application {
  ...
  /* basic task */
  TASK myTask1 {
    STACK = SHARED ;
    ...
  };
  /* basic task with a separate stack */
  TASK myTask2 {
    STACK = PRIVATE {
      SIZE = 128;
    };
  };
  /* extended task (because it uses an event) with a separate stack */
  TASK myTask3 {
    STACK = PRIVATE {
      SIZE = 128;
    };
    EVENT = myEvent;
  };
  /* extended task (explicitly marked) with a separate stack */
  TASK myTask4 {
    STACK = PRIVATE {
      SIZE = 128;
      EXTENDED = TRUE;
    };
  };
  ...
};

The ISR Object

The ISR object is used to specify the ISR Handlers in the system. Depending on the architecture, RT-Druid will also program the interrupt vector, set the interrupt priorities, set the interrupt routing, and so on.

The name of the object is the interrupt handler C function which must be present in the application or driver code. Some architectures may fix the names of these interrupts.

The attributes of this object are:

  • CPU_ID is the CPU identifier (the default is 0).
  • CATEGORY is the kind of interrupt.
    • Category 1 ISR cannot call many OS Primitives.
    • Category 2 can call OS Primitives.
    • This attribute is specified by the OSEK standard.
  • RESOURCE is the list of resources using the ISR. Locking a resource that is also used by an ISR means raising the interrupt controller priority to the maximum value of the ISR priorities.
    • This attribute is specified by the OSEK standard.
  • SOURCE the interrupt source id or source number (architecture dependent, string).
  • PRIORITY the interrupt priority.
  • HANDLER if defined, this is the name of the function, otherwise the ISR name is used as function name.
  • TRAP if TRUE, identifies a TRAP (architecture dependent). In this case CATEGORY and PRIORITY are ignored.";

Example:

CPU mySystem {
  ISR ButtonsISR {
    CATEGORY = 2;
    SOURCE   = "PORTC";
    PRIORITY = 1;
  };
};

The Resource Object

The RESOURCE object is contained inside the CPU object and it is used to specify the properties of a resource. The Resource object contains an attribute named RESOURCEPROPERTY which can take the following values:

  • STANDARD is the default used for a normal resource.
  • LINKED resources are only links/alias for other resources.
  • INTERNAL resources are resources which are locked when the task starts, and unlocked when the task ends (or when the Schedule primitive is called). They can be used to implement Preemption Thresholds.

Example:

CPU mySystem {
  RESOURCE mymutex { RESOURCEPROPERTY = STANDARD; };
  ...
};

The Event Object

The EVENT object is used to define a bit mask which then can be used by extended tasks. Events with the same name are identical, and have the same mask. Events with the same mask are not identical. If the value AUTO is specified for a mask, then RT-Druid automatically computes the mask value.

Example:

CPU mySystem {
  EVENT myEvent1 {
    MASK = 0 x01;
  };
  EVENT mtEvent2 {
    MASK = AUTO;
  };
  ...
};

The Counter Object

The COUNTER object is the timing reference that is used by alarms. The attributes of a counter are the following:

  • CPU_ID is an indication of the CPU on which the counter is mapped. The default value is 0. If the identifier of the CPU does not exist in the system, an error is generated.
  • MINCYCLE this is the minimum value that can be given to the cycle parameter of an alarm (used for example in SetRelAlarm
  • MAXALLOWEDVALUE is the maximum value of the counter. The tick after the maximum will wrap around to 0.
  • TICKSPERBASE this is a hardware prescaler. This parameter says how many hardware ticks (or calls to IncrementCounter are needed to increment by one the counter.
  • SECONDSPERTICK this is the period in seconds of the timer. In the case of the system timer, it is used to program the periodic timer interrupt.
  • TYPE can be either SOFTWARE (default) or HARDWARE.
    when HARDWARE, the kernel creates a customized handler linked to a timer. in order to do that, there are a set of additional options that needs to be specified:
    • SYSTEM_TIMER can be TRUE or FALSE. When true, it is handled as the OSEK/VDX suystem timer
    • PRIORITY is the IRQ priority of the hardware timer linked to this counter.
    • DEVICE is a string that specifies one of the hardware devices that can be configured as hardware timer. The list of hardware devices available for hardware timers is in the wiki page of the architecture port.
    • HANDLER specifies the handler of the hardware counter.

Example:

CPU mySystem {
  COUNTER SystemTimer {
    MINCYCLE = 1;
    MAXALLOWEDVALUE = 65535;
    TICKSPERBASE = 1;
    TYPE = HARDWARE {
      SYSTEM_TIMER = TRUE;
      PRIORITY     = 1;
      DEVICE       = "SYSTICK";
    };
    SECONDSPERTICK = 0.001;
  };
  COUNTER myTimer {
    MINCYCLE = 32;
    MAXALLOWEDVALUE = 127;
    TICKSPERBASE = 23;
  };
  ...
};

The Alarm Object

The ALARM Object is used to implement an asynchronous notification which can activate a task, set an event or call a callback function.

Alarms can be autostarted at boot time depending on the application mode.

The attributes of an alarm are the following:

  • COUNTER specifies the counter to which the alarm is statically linked.
  • ACTION specifies the kind of action which has to be implemented when the alarm fires. The action is specified using one of the following sub-attributes:
    • ACTIVATETASK specifies that a task has to be activated. The name of the task must be specified inside the TASK sub-attribute.
    • SETEVENT specifies that an event has to be set on a task. The task name and event must be specified inside the TASK and EVENT sub-attributes.
    • ALARMCALLBACK specifies that an alarm callback has to be called. The name of the callback is specified inside the attribute ALARMCALLBACKNAME.
    • INCREMENTCOUNTER specifies that another counter has to be incremented. The name of the counter is specified in the COUNTER sub-attribute.
  • AUTOSTART specifies if the alarm has to be autostarted at system startup. If TRUE, the alarm properties and the application modes for which the alarm should be autostarted have to be specified in the sub-attributes ALARMTIME, CYCLETIME, and APPMODE.

Example:

CPU mySystem {
  ALARM AlarmTask1 {
    COUNTER = SystemTimer;
    ACTION = SETEVENT { TASK = Task1; EVENT = TimerEvent; };
    AUTOSTART = TRUE { ALARMTIME = 250; CYCLETIME = 1000; };
  };
  ALARM AlarmTask2 {
    COUNTER = SystemTimer;
    ACTION = ACTIVATETASK { TASK = Task2; };
    AUTOSTART = FALSE;
  };
  ...
};

The SCHEDULETABLE Object

The SCHEDULETABLE object are ALARMs on steroid, they let you completly describe the temporal relation of a set TASK's activations and/or TASK's events. If the TASK set relation is completly static, could be described by a set of ALARMs, but if you need to adjust relative scheduling between these entities at run time, it has to be done manually in a critical section (at least OS level interrupts suspended). Schedule Tables address the relative synchronization problem between TASK's activations

They do that by providing an encapsulation of a statically defined set of expiry points. Each expiry point defines:

  • one or more actions that must occur when it is processed where an action is the activation of a TASK or the setting of an EVENT.
  • An offset in ticks from the start of the schedule table

Each schedule table has a duration in ticks. The duration is measured from zero and defines the modulus of the schedule table.

SCHEDULETABLEs can be autostarted at boot time depending on the application mode.

The attributes of a schedule table are the following:

  • COUNTER specifies the counter to which the schedule table is statically linked.
  • DURATION specifies the schedule table duration in counter ticks.
  • AUTOSTART specifies if the alarm has to be autostarted at system startup. If TRUE, the following startup prperties have to be specified
    • START_VALUE Value of the linked counter when to start the schedule table
    • APPMODE Can be repeated multiple time, one for each appmode that has to autostart the schedule table. If no APPMODE is specified the schedule table is in autostart in all the appmode configured.
  • EXPIRY_POINT It is a point in time inside schedule table duration when execute a list of actions. Multiple expiry point can be configurated each of them with a different value of EXPIRE_VALUE.
    • EXPIRE_VALUE Offset in counter ticks from the start of the schedule table, when the expiry point is processed.
    • ACTION Can be reapeted multiple time inside an expiry point, it represent an action executed when the expiry point is reached. All the actions specified are executed sequentially during the expiry point handling. The action is specified using one of the following sub-attributes:
      • ACTIVATETASK specifies that a task has to be activated. The name of the task must be specified inside the TASK sub-attribute.
      • SETEVENT specifies that an event has to be set on a task. The task name and event must be specified inside the TASK and EVENT sub-attributes.
 SCHEDULETABLE SchedTab1 {
   COUNTER = system_timer;
   DURATION = 500;
   AUTOSTART = TRUE {
     START_VALUE = 10;
   };
   EXPIRE_POINT = ACTION {
     EXPIRE_VALUE = 100;
     ACTION = ACTIVATETASK { TASK = Task2; };
   };
   EXPIRE_POINT = ACTION {
     EXPIRE_VALUE = 400;
     ACTION = ACTIVATETASK { TASK = Task2; };
   };
 };

N.B. ScheduleTable are designed to have to two types of synchronization:

  • Implicit to the internal counter
  • Explicit done by "application" trough SyncScheduleTable, primitive

Since explicit synchronization is not yet completly implemented all the fields of SCHEDULETABLE object used for explicit synchronization are not described, yet.

The SPINLOCK Object

Spinlocks are mutual exclusion mechanism valid for a multicore environment, actually only the TriCore porting is a multicore porting and support spinlocks.

Spinlocks are accessible by all cores, to allow nested acquisition a unique order have to be specified, otherwise only one spinlock can be acquired by one core at any time. To provide unique order the NEXT_SPINLOCK field have to be populated with the reference to the next spinlock in list. As in the following example

 SPINLOCK spinlock_1 { NEXT_SPINLOCK=spinlock_2; };
 SPINLOCK spinlock_2 { NEXT_SPINLOCK=spinlock_3; };
 SPINLOCK spinlock_3 { NEXT_SPINLOCK=spinlock_4; };
 SPINLOCK spinlock_4 {};

Is not necessary that a core holds all the spinlocks in list, it only needs to never get back in that list. So acquiring spinlock_1, spinlock_3 and then spinlock_4 is perfectly fine, acquiring spinlock_2 instead is not, it has to release at least spinlock_2 before doing that

Dynamic APIs

IMPORTANT: The support for the dynamic API is EXPERIMENTAL and not aimed for production.

Dynamic API in ERIKA3 identify a set of functionality that allow the kernel configuration to be stored in the application source code and not statically configured in the OIL File. The main idea is that RT-Druid generates a set of empty data structures, whcih are then filled before being used (typically before calling StartOS).

Therefore, the OIL file only contains a set of information needed to provide the size of the data structures. This is done in the OS object by setting USEDYNAMICAPI to TRUE and specifying the various sizes as in the following example:

CPU myCPU {
  OS myOS {
    USEDYNAMICAPI = TRUE {
      TASK_ARRAY_SIZE = 6;
      SN_ARRAY_SIZE = 6;
      STACKS_MEMORY_SIZE = 2048;
    };
  };
};

...and in the specification of the MQ parameter (ref).

After that, in the application source code, typically in the main() function, the tasks are initialized by calling the appropriate functions, as in the following example:

#if (defined(OSEE_API_DYNAMIC))
  InitOS();
  
  CreateTask( &Task1, OSEE_TASK_TYPE_EXTENDED, TASK_FUNC(Task1),
      1U, 1U, 1U, 512U );
  CreateTask( &Task2, OSEE_TASK_TYPE_BASIC, TASK_FUNC(Task2),
      2U, 2U, 1U, 512U );
  CreateTask( &IsrTimerId, OSEE_TASK_TYPE_ISR2, TimerISR,
      1U, 1U, 1U, OSEE_SYSTEM_STACK );
  CreateTask( &IsrButtonsId, OSEE_TASK_TYPE_ISR2, ButtonsISR,
      1U, 1U, 1U, OSEE_SYSTEM_STACK );
  ...
#endif

The Dynamic API currently only support tasks.

See also

EForms Oil Editor