wp10 -d10.8 programmer's guide - mnis

306
WP10 -D10.8 WP10 -D10.8 Programmer's Programmer's Guide Guide

Upload: others

Post on 12-Apr-2022

11 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: WP10 -D10.8 Programmer's Guide - MNIS

WP10 -D10.8 WP10 -D10.8 Programmer'sProgrammer's

GuideGuide

Page 2: WP10 -D10.8 Programmer's Guide - MNIS

I) DocumentPresentation

Project Coordinator

Organisation:UPVLCResponsible person:Alfons Crespo

Address:Camino Vera, 14, 46022 Valencia,Spain

Phone:+34 963877576Fax:+34 963877576

Email:[email protected]

Participant List

Role Id. Participant Name Acronym Country

CO 1Universidad Politecnica deValencia

UPVLC E

CR 2 Scuola Superiore Santa Anna SSSA I

CR 3Czech Technical University inPrague

CTU CZ

CR 4 CEA/DRT/LIST/DTSI CEA FRCR 5 Unicontrols UC CZCR 6 MNIS MNIS FRCR 7 Visual Tools S.A. VT E

Document version

Release Date Reason of change1_0 15/02/2004 First release1_1 15/11/2004 Extend the configuration part 1_2 15/02/2005 Rewrite installation part, configuration part,

add components, applications

Page 3: WP10 -D10.8 Programmer's Guide - MNIS
Page 4: WP10 -D10.8 Programmer's Guide - MNIS

Forword that must disapear asap

This document is still in a draft version, the following actions are to be done toget the document in a final version:

1) verify the names of the chapter's authors

2) Index for tables and figures

3) Glossary

4) a standard figure caption style all along the documentation

5) chapters missing: Onetd: network interface programing by Pierre Morel

6) chapter missing: Driver's framework

7) Re-reading and corrections by Ocera members

Page 5: WP10 -D10.8 Programmer's Guide - MNIS

Table of Contents

Document Presentation.............................................................. ........................2

Introduction............................................................................................. .............6

Overview........................................................................... ................................6What will you find in the Programmer's Guide..................................................7What will you NOT find in the Programmer's Guide..................................... .....8

Overview............................................................................................. ..................9

OCERA architecture....................................................................................... ...9How RTLinux and Linux work together...........................................................13Supported target......................................................... ....................................18Development tools.................................................... ......................................18

RTLinux API............................................................................... ........................21

Dynamic memory allocator.............................................................................. 21POSIX Signals................................................................................. ................24POSIX Timers....................................................................... ..........................27POSIX message queues......................................................................... ........30Posix Barriers.......................................................................................... ........31Application-Defined Scheduler.................................................................. ......37Ada Support.............................................................................. ......................48POSIX tracing.................................................................................. ................52

Quality Of Services.................................................................................... ........70

OCERA Real-Time Ethernet.................................................................... ..........73

struct ORTEIFProp.................................................................................... ......76struct ORTEMulticastProp............................................................................. ..77struct ORTECDRStream............................................................. ....................79struct ORTETypeRegister......................................................... ......................80

Page 6: WP10 -D10.8 Programmer's Guide - MNIS

struct ORTEDomainBaseProp.......................................... ..............................81struct ORTEPubInfo............................................................................ ............88struct ORTETasksProp....................................................... ............................95struct ORTEDomainProp........................................ ........................................96

Fault-Tolerance components................................... ......................................140

Degraded Mode Management........................... ...........................................140Redundancy Management.......................................................... ..................158

CAN................................................................................................................. ..169

Installation......................................................................................... ............169API / Compatibility................................................................................... ......171

Page 7: WP10 -D10.8 Programmer's Guide - MNIS

PART IPART IProgramming environment

Page 8: WP10 -D10.8 Programmer's Guide - MNIS

II) Introduction

By Pierre Morel - MNIS

This is the OCERA Programmer's Guide. We will try through this document tohelp you programming with OCERA.In this first chapter we will explain the goal of this guide, we assume that youalready read the User's Guide, so that you are familiar with the concepts used allalong the guide.

1) Overview

1.1) Intended Audience

This guide is intended for - software engineers who are building a real time embedded application

for commercial or educational use with OCERA.- teachers who want to rapidly build a real-time plate-form for training of

students. In this case the teachers will also have interest in the OCERAdocument named TRAINING DOCUMENTATION AND CASE STUDIES, wherethey will find ready to use training examples.

Page 9: WP10 -D10.8 Programmer's Guide - MNIS

1.2) Pre-requisite:

To use OCERA kernel and components and understand how they work togetheryou will need a basic knowledge on how an Operating System is working,both for real-time OS and time sharing OS, and for some of the components, abasic knowledge of TCP/IP network architectures.

To develop applications using OCERA you will need some skills in adevelopment language, C is the standard language for OCERA, while C++ isused in ORTE and Ada is supported for application's programming.Depending on the developments you intend to do and which components youintend to use and certainly a knowledge of POSIX thread programming wouldhelp a lot.

2) What will you find in theProgrammer's Guide

The Programmer's guide will present you • The OCERA environment where your application will execute:

Linux and RTLinux, the OCERA Architecture. How they worktogether.

• Programming in for Hard Real-Time: the real-time ApplicationProgramming Interface, the tools you will need to compile yourapplication and to let it run with the system.

• Programming in for Soft Real-Time: the soft real-timeApplication Programming Interface, the tools you will need tocompile your application and to let it run with the system.

• A driver's framework, and how to write drivers in Linux takingcare of the real-time necessities.

• RTLinux/Linux Interfaces: Interfaces between the real-timesystem and the time sharing system.

Page 10: WP10 -D10.8 Programmer's Guide - MNIS

• Qconf programming: The way to add new components to theOCERA tree

• The components and the programming interface to the differentcomponents of OCERA like Fault Tolerance, CAN CAN/OpenInterface and ORTE: OCERA Real Time Ethernet

3) What will you NOT find in theProgrammer's Guide

The Programmer's guide will not present you a general aspect of OCERA nor willit present to you how to setup the development environment or to setup a crosscompiler environment.All these features are presented in the OCERA User's Guide.

Page 11: WP10 -D10.8 Programmer's Guide - MNIS

III) Overview

By Pierre Morel – MNIS

1) OCERA architecture

1.1) RTLinux-GPL

Original RTLinux-GPL architecture can be divided in two levels: • A basic real-time operating system, handling interrupts and

providing a minimal development interface for real-time threads. We willsometime refer to this level by simply RTLinux-GPL. It is a Hard real-time level with interrupt latency and thread switch latency in the orderof a few tens of micro seconds (on a PIII-1GHZ).

• A time sharing operating system, the Linux level, having the fullfunctionalities of the original Linux operating system, and running as theidle thread of the basic real-time system.

Both operating systems co-operate in many ways:• interrupts: the original Linux Operating system is modified so that it

does not do any direct hardware access for interrupts handling, lettingthe work to be done by RTLinux-GPL. If a Linux ISR is associated withthe Interrupt, RTLinux-GPL, mark the Interrupt as to be served andcalls the Linux handlers as soon as nothing more is to be done at real-time level.

Page 12: WP10 -D10.8 Programmer's Guide - MNIS

• Realtime-FIFO: if a real-time thread and a Linux task want to exchangedata, they can do it through real-time fifo, this is a good way to ensure aproper switch between the real-time OS and the shared time OS. Thereal-time fifo use soft IRQ to synchronize the Linux task and the real-time thread.

• Shared Memory: is another way to exchange data between Linux andRTLinux-GPL. The synchronization must be done by the application byatomic_test_and_set() calls for exemple.

• BSD Socket: an implementation of the BSD Socket interface for UDPprotocol allow a real-time thread and a Linux process to communicate.The synhronization, as with the real-time FIFOs is done by Soft-IRQs.

We also found of great interest to have the possibility to add a soft real-time levelto Linux, using and enhancing the LOW LATENCY and the PREEMPTIONpatches, this are the first bricks to provide Soft real-time and Quality Of Serviceat the Linux (shared time OS) level, and then to applications running on Linux,like Video Streaming.You can see a much deeper description of the architecture in the document“OCERA ARCHITECTURE” D02-1.pdf and we advise you to do so if you want tohave a good understanding of the internals of OCERA.

1.2) The components

We define a component as:„A piece of software that brings some new functionality or feature at different

levels in some of the fields: Scheduling, Quality Of Service, Fault Toleranceor Communications.“

Remember that our goal is to enhance an existing Operating system, RTLinux-GPL, to achieve an industry ready operating system and that to achieve thiswant to give RTLinux:

• A real POSIX 1.1 development interface and new scheduling algorithmand new synchronization mechanisms for RTLinux.

• Quality Of Service, to allow bandwidth reservation• Fault Tolerance and reconfiguration• Communication with industry standard control/command devices

All the component interact with some of the other components:

a) Communication

CANBUS

CANBUS drivers works under Linux and/or RTLinux and provides a virtualinterface for testing and development purpose under Linux.

Page 13: WP10 -D10.8 Programmer's Guide - MNIS

We will explain deeper the CANBUS drivers and the usage of the drivers in thechapter XX: CANBUS.

Socket Interface

A BSD like socket interface provides access to the network for the RealTimethreads by using the Linux socket implementation.We will explain deeper the socket interface and its usage in the chapter XX:Onetd.

ORTE

ORTE stands for OCERA Real Time Ethernet and implements the Real TimePublisher Subscriber protocol.The RTSP protocol allow publishers to reserve some of the ethernet bandwidthand manage this reservation so that the bandwidth allocated for each participantallow the data transfert time over ethernet to be predictable.ORTE is able to work under Linux or under RTLinux with the Onetd socketinterface, the choice is made at compile time.We will see ORTE in deep in the chapter XX: ORTE.

b) Fault Tolerance

Fault tolerance can collaborate with the Quality Of Service component to handlebudget reservation exceptions.In the case of a distributed network, Fault Tolerance must use a real-time awarecommunication protocol like the RTSP protocol implemented by thecommunication component ORTE.We will investigate the way to use Fault Tolerance in deep in the chapter XX:Faul Tolerance

c) Quality Of Service

Quality Of Service in OCERA allows a Linux Process to do a CPU Bandwidthreservation.This means that, the process having done this reservation is given access to theCPU at regular times without the influence of any other processes.This has the following implications:

• First, the Linux Scheduler must be made preemptive. To do this wehave to use the preemptive patch for Linux. We also reduced the Linuxlatency by using the low latency patch.

• Second the Linux scheduler algorithm must be modified to allow a CBSConstant Bandwidth Scheduler, algorithm.

• Third, in the case of Linux working over RTLinux-GPL, RTLinux-GPLscheduling algorithm must be changed to also allow a CBS algorithm.

• Fourth: both Linux and RTLinux scheduler must be aware of thebandwidth reservation

Page 14: WP10 -D10.8 Programmer's Guide - MNIS

This Quality Of Service is, for example, very useful in the case we have real timeconstraint at both Linux and RTLinux levels.A good exemple for this is the real time video streaming application made byVisual Tools and presented at the end of this guide.We will go deeper in the way to use the Quality Of service in the chapter XXX:Quality Of Service.

d) RTLinux components

RTLinux-GPL had to be enhanced to achieve our goals. As we saw earlier, wehave to provide a POSIX 1.1 development interface, and modify the schedulingalgorithm.By the way OCERA integrated new components: a socket interface used by theRTLinux-GPL implementation of ORTE and Ada runtime.We will see all POSIX components in the Programmer's Guide, and we will takea look at the possibilities offered by the Onetd Socket interface in the chapterXXX and at the Ada runtime in the chapter XX.

Page 15: WP10 -D10.8 Programmer's Guide - MNIS

Illustration 1 Overview of OCERA implementation

Page 16: WP10 -D10.8 Programmer's Guide - MNIS

2) How RTLinux and Linux worktogether

To understand this chapter, internal knowledge of Linux kernel and knowledgeof the way Linux modules works is a good think.However an engineer with good knowledge of operating systems will understandthe way RTLinux takes control of Linux without deep Linux kernel knowledge.

2.1) Taking control

RTLinux takes control over the Linux kernel as the rtlinux.o module is loaded.The __init routine of the rtlinux.o module calls the "self explained" functionarch_take_over.

A light version of this function is shown here under. In particular we do not detailSMP architecture initialization or #define preprocessing here to simplify thepresentation. Of course, you can browse the source to see the details of theroutine.

arch_takeover rtl_hard_cli rtl_global.flags = g_initialized rtl_local.flags = l_ienable | l_idle rtl_reschedule_handlers = default_reschedule_handler patch_kernel rtl_hard_sti rtl_soft_sti

As one can see, after clearing interrupts and doing some initialization, the routineinitialize the reschedule_handler and then calls the once again "self explained"function patch kernel routine.

patch_kernel xdo_IRQ = pfunc[pf_do_IRQ].address (pfunc is a table of functions) local_ret_from_intr = pfunc[pf_ret_from_intr].address p=find_patch(pfunc[pf_do_IRQ].address

Page 17: WP10 -D10.8 Programmer's Guide - MNIS

save_jump(p,pf_do_IRQ) patch_jump(p,rtl_intercept) pfunc[pf_rtl_emulate_iret] = rtl_soft_sti IF LOCAL_APIC save_jump(LOCALS_PATCHS) zap_ack_apic init_local_code pre_patch_control=irq_control irq_control.do_save_flags = rtl_soft_save_flags irq_control.do_restore_flags = rtl_soft_restore_flags ...etc replace cli/sti local_irq_save,restore,disable and enable ... for i < NB_IRQS save_linux_irq_desc = h.handler h.handler = rtl_generic_type

This functions setup the interrupt routine local_ret_from_intr to the address ofrtl_intercept it then patches the APIC subroutines if a APIC exists by callingzap_ack_apic and init_local_code and initialize the irq_control which contains theaddress of the routines that will replace the standard Linux routines:

• do_save_flags• do_restore_flags• cli• sti• local_irq_save• local_irq_restore• local_irq_enable• local_irq_disable

2.2) Interrupt handling

The interrupts are processed in four levels. The first three levels are calledwhenever an interrupt is called they are:

• rtl_intercept the real interrupt routine called when the interrupt arrives andresponsible for the APIC handling and interrupt acknowledge.

• dispatch_rtl_handler dispatch the interrupts to the Real Time handlers.

• dispatch_linux_irq dispatch the interrupts to the Linux interrupt handlers.

The main interrupt routine is detailed here under:

rtl_intercept rtl_spin_lock(rtl_global.har_irq_controller_lock) if rtl_irq_controller_get_irq

Page 18: WP10 -D10.8 Programmer's Guide - MNIS

rtl_irq_controller_ack if G_TEST_RTH (test if IRQ is for RTLinux) rtl_spin_unlock dispatch_rtl_handler rtl_spin_lock else G_PEND (set IRQ as pending) G_SET(g_pend_since_sti) (set flags IRQ pending) if RUN_LINUX_HANDLER (irq enabled and RT not busy) G_UNPENd rtl_soft_cli G_DISABLE rtl_spin_unlock rtl_hard_sti dispatch_linux_irq RETURN_FROM_INTERRUPT_LINUX (simple return) rtl_spin_unlock RETURN_FROM_INTERRUPT (pop all and IRET)

The fourth level is the soft_irq level for linux. This is called whenever the RTLinuxscheduler has finished to dispatch the real time tasks. See the details on the realtime scheduling in the next section.

global flags: g_rtl_started g_pend_since_sti g_initializing g_initialized

Local flags: l_busy 1 if RTLinux is scheduling a RT task l_ienable 1 if soft sti emulation (cli/sti) l_pend_since_sti 1 if irq pending since last sti l_psc_active old flag for memory protection PSC module.

Macro: G_PEND,G_UNPEND,G_ISPEND: 1 if global irq pending G_ENABLE,G_DISABLE,G_ISENABLE: 1 if irq is globally soft enabled G_SET_RTH,G_CLEAR_RTH,G_TEST_RTH: 1 if RT Handler set for irq G_SET,G_CLEAR,G_TEST: 1 if global flag set

L_PEND,L_UNPEND,L_ISPEND: local version L_SET,L_CLEAR,_L_TEST: local version L_SET_RTH,L_CLEAR_RTH,L_TEST_RTH: local version

a) Structures for the transition

rtl_global_handlers[irq] : table for RT Handlers set: rtl_request_global_irq

Page 19: WP10 -D10.8 Programmer's Guide - MNIS

clear: rtl_free_global_irq used: rtl_intercept activate: G_PEND(irq) and G_SET(g_pend_since_sti)

irqaction * set: rtl_get_soft_irq (handler) -> request_irq -> setup_irq activate: rtl_global_pend_irq: G_PEND and G_SET(g_pend_since_sti)

b) LINUX:

do_IRQ -> handle_IRQ_event -> action->handler() -> desc->handler->end() -> do_softirq()

2.3) Scheduling

Every time a call is done to irq_control.do_sti (which replace the sti call), thefunction do_soft_sti is called this function calls rtl_process_pending before to callthe rtl_soft_sti_no_emulation function to setup the local ienable.

rtl_process_pending rtl_soft_cli do while get_lpended_irq soft_dispatch_local while get_gpending_irq soft_dispatch_global while G_TEST(g_pend_since_sti | l_pend_since_sti if softirq_active(cpu_id) do_softirq /*kernel/softirq*/G

Page 20: WP10 -D10.8 Programmer's Guide - MNIS

3) Supported target

Basicaly, OCERA is able to support all targets supported by RTLinux-GPL andLinux. The most restrictive being RTLinux-GPL.OCERA support architectures based on

• Intel ix86, • powerPC 603e / Mototola 8240• ARM and Strong ARM,

while the Board Support Package (BSP) include: • Standard PC• PC104• PPC6000• iPAQ

The OCERA system can be loaded on the target on IDE and SCSI disks, Flashmemory, SD-Memory, ROM or even use the network to be downloaded usingTFTP or BootP and a PXE boot loader in ROM..We provide more information on the different architectures and on crosscompilation in the OCERA User's Guide.

4) Development tools

The tools used to develop applications with OCERA are of very common use:The GNU Utilities: the GNU C compiler, assembler, linker,

Page 21: WP10 -D10.8 Programmer's Guide - MNIS

The CML2 Utilities: CML2 is the definition language used by the standard Linuxkernel, above 2.5.2, to define the kernel configurationTo this minimal set of utilities, you will eventually need the OCERA tracing toolsor the GNU Debugger: GDB.If you develop with Ada language you will need a special Ada compiler. But thiswill be explained in a separate chapter dedicated to Ada in this document.

Page 22: WP10 -D10.8 Programmer's Guide - MNIS

PART II PART II Realtime programming

Page 23: WP10 -D10.8 Programmer's Guide - MNIS

IV) RTLinux API

By:Patricia BalbastreAlfons CrespoIsmael Ripoll

1) Dynamic memory allocator

1.1) Description

This component provides standard dynamic memory allocation, malloc and freefunctions, with real-time performance.

1.2) Usage

The component is designed to work in three different targets:

1) as a Linux user level library, 2) in the Linux kernel, and 3) in RTLinux.

The target dependent code is surrounded by conditional directives thatautomatically compiles the final object file to the correct target depending on theset of defined macros: __RTL__, __KERNEL__, etc.

Page 24: WP10 -D10.8 Programmer's Guide - MNIS

When the bigphysarea patch is available in the kernel, the allocator will use thisfacility by default. Therefore the maximum memory pool will be limited by thememory initially (at boot time with the kernel parameter "mem") allocated bybigphysarea.

When the allocator is compiled as a kernel module (to by used from the Linuxkernel or by RTLinux applications), the name of the module is rtl_malloc.o; it canbe loaded using the rtlinux script:

# rtlinux startScheme: (-) not loaded, (+) loaded (+) mbuff (+) rtl (+) rtl_fifo (+) rtl_malloc (+) rtl_posixio (+) rtl_sched (+) rtl_time

The module accepts the parameter "max_size" which is the size of the initialmemory pool in Kbytes. If the parameter is not passed to the module then thedefault initial memory pool size is 1Mbyte. In order to use more than 1Mb youhave to manually load the module.

1.3) Programming interface (API)

In order to avoid naming conflicts, the API provided by DIDMA is non POSIX, itlooks like the API given by the ANSI "C" standard adding a rt_ prefix.

void *rt_malloc(size_t *size); void rt_free(void *ptr); void *rt_calloc(size_t nsize, size_t elem_size); void *rt_realloc(void *p, size_t new_len); And it also provides several macros which are equal than ANSI-C functions interface fordynamic memory allocation:void *malloc(size_t *size); void free(void *ptr); void *calloc(size_t nsize, size_t elem_size); void *realloc(void *p, size_t new_len);

1.4) Example

#include \<rtl_malloc.h\>#include \<rtl.h\>#include \<pthread.h\>

Page 25: WP10 -D10.8 Programmer's Guide - MNIS

pthread_t thread;

void * start_routine(void *arg){ char *string; char hello_world [] = "Hello world";

rtl_printf("Calling malloc... "); // DIDMA malloc string = (char *) malloc (sizeof (char) * (strlen (hello_world) + 1));

if (string == NULL) { rtl_printf("WRONG\n"); return (void *) 0; } rtl_printf("Malloc OK\n"); strcpy (string, hello_world); rtl_printf ("HELLO_WORLD: %s\n", hello_world); rtl_printf ("HELLO_WORLD copy: %s\n", string); rtl_printf("Calling free... ");

// DIDMA free free (string);

rtl_printf("DONE\n"); return (void *)0;}

int init_module(void){ return pthread_create (&thread, NULL, start_routine, 0);}

void cleanup_module(void){ pthread_delete_np (thread);}

Page 26: WP10 -D10.8 Programmer's Guide - MNIS

2) POSIX Signals

2.1) Description

This component extends the signalling subsystem of RTLinux to provide user-defined signals and the user signal handlers.

Signals are an integral part of multitasking in the UNIX/POSIX environment.Signals are used for many purposes, including exception handling (bad pointeraccesses, divide by zero, etc.), process notification of asynchronous eventoccurrence (timer expiration, I/O completion, etc.), emulation of multitasking andinterprocess communication.

A POSIX signal is the software equivalent of an interrupt or exceptionoccurrence. When a task receives a signal, it means that something hashappened which requires the task s attention. Because a thread can send asignal to another thread, signals can be used for interprocess communication.Signals are not always the best interprocess communication mechanism; theyare limited and can asynchronously interrupt a thread in ways that require clumsycoding to deal with. Signals are mostly used for other purposes, like the timerexpiration and asynchronous I/O completion. There are legitimate reasons forusing signals to communicate between processes. First, signals are frequentlyused in UNIX systems. Another reason is that signals offer an advantage thatother communication mechanisms do no support: signals are asynchronous.That is, a signal can be delivered to a thread while the thread is doing somethingelse. The advantages of asynchrony is the immediacy of the notification and theconcurrence.

This facility provides only regular UNIX(r) signalling infrastructure. Although real-time POSIX extensions defines an advanced and powerful signal system, itscomplexity make the implementation more complex and less predictable (sincethe standard requires that signals can not lost and also delivered in the sameorder it were generated, then signals can not be internally implemented asbitmaps but lit must be handled as message queues) .

Page 27: WP10 -D10.8 Programmer's Guide - MNIS

2.2) Usage

This facility is optional and has to be selected in the configuration tool. Thiscomponent is integrated into the RTLinux scheduler module. The functionality isavailable once the rtl_sched.o module is loaded.

2.3) Programming interface (API)

struct rtl_sigaction { union { void (*_sa_handler)(int); void (*_sa_sigaction)(int, struct rtl_siginfo *, void *); } _u; int sa_flags; unsigned long sa_focus; rtl_sigset_t sa_mask; };/* Macros to manupulate POSIX signal sets.*/rtl_sigaddset(sigset_t *set, sig);rtl_sigdelset(sigset_t *set, sig); rtl_sigismember(sigset_t *set, sig); rtl_sigemptyset(sigset_t *set); rtl_sigfillset(sigset_t *set);/* Programing actions for signals ocurrences*/ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); /* Set the process s signal blockage mask */ int sigprocmask(int how, const rtl_sigset_t *set, rtl_sigset_t *oset); int pthread_sigmask(int how, const rtl_sigset_t *set, rtl_sigset_t *oset); /* Wait for a signal to arrive, setting the given mask */ int sigsuspend(const rtl_sigset_t *sigmask); int sigpending(rtl_sigset_t *set); /* Send a signall to a thread */int pthread_kill(pthread_t thread, int sig);

This is the standard POSIX API and it is used as the standard defines.Documentation about how signals are programmed can be found in any bookabout UNIX programming.

2.4) Example

/* * POSIX.1 Signals test program * */

#include <rtl.h>#include <rtl_sched.h>

Page 28: WP10 -D10.8 Programmer's Guide - MNIS

#define MAX_TASKS 2#define MY_SIGNAL RTL_SIGUSR2static pthread_t thread[MAX_TASKS];

static void signal_handler(int sig){ rtl_printf(">--------------------------------------->\n"); rtl_printf("Hello world! Signal handler called for signal:%d\n",sig);}

static void * start_routine(void *arg) { int i=0,err=0,signal; struct sched_param p; struct sigaction sa; rtl_sigset_t set;

p.sched_priority = 1; pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);

signal=MY_SIGNAL+(unsigned) arg; rtl_sigfillset(&set); rtl_sigdelset(&set,signal); pthread_sigmask(SIG_SETMASK,&set,NULL);

sa.sa_handler=signal_handler; sa.sa_mask=0; sa.sa_flags=0; sa.sa_focus=0;

if ((err=sigaction(signal,&sa,NULL))<0 ) rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d, errno:%d.\n", signal,err,errno);

pthread_make_periodic_np (pthread_self(), gethrtime(), 250000000LL+250000000LL * (unsigned) arg);

rtl_printf("I'm here; my arg is %x iter:%d\n",(unsigned) arg,i++); rtl_printf("When i mod 5 -> pthread_kill(pthread_self(),%d)\n",signal);

while (i<=10) { pthread_wait_np (); if (!(i%5)) pthread_kill(pthread_self(),signal); rtl_printf("I'm here; my arg is %x iter:%d\n",(unsigned) arg,i++); }

rtl_printf("\n\n\n THREAD %d about to end\n\n\n",(unsigned) arg); return 0;}

int init_module(void) { int i,err=0; for (i=0;i<MAX_TASKS;i++) err=pthread_create (&thread[i], NULL, start_routine,(void *) i); return err;}

void cleanup_module(void) {

Page 29: WP10 -D10.8 Programmer's Guide - MNIS

int i; for (i=0;i<MAX_TASKS;i++) pthread_delete_np (thread[i]);}

3) POSIX Timers

3.1) Description

POSIX timers provides mechanisms to notify a thread when the time (measuredby a particular clock) has reached a specified value, or when a specified amountof time has passed.

This component provides the functionality to work with several timers per thread.Timer expiration is notified to the thread by mean of a POSIX signal.

3.2) Usage

Since a timer expiration causes a signal to be delivered, this facility depends onsignal support. To use POSIX timers first you have to select POSIX signals andthen select POSIX signals: OCERA Components Configuration -> Scheduling.

This facility is included into the standard scheduler module (rtl_sched.o).Therefore, once the scheduler compiled with timers support is generated and themodule is loaded, the user can use the new functions.

3.3) Programming interface (API)

Data structure used to specify which action will be performed upon timerexpiration:

Page 30: WP10 -D10.8 Programmer's Guide - MNIS

struct sigevent { int sigev_notify; /* notification mechanism */ int sigev_signo; /* signal number */ union sigval sigev_value; /* signal data value */ }

Currently, only two values are defined for sigev_notify: SIGEV_SIGNAL meansto send the signal described by the remainder of the struct sigevent; andSIVEV_NONE which means to send no notification at all upon timer expiration.

Next are the system calls to create and delete timers and for arming andconsulting the state of an armed timer.

/* Creating a timer. Timer created is returned in timer_id location */int timer_create(clockid_t clockid, struct sigevent *restrict evp, timer_t *restrict timer_id);/* Removing timer referenced by timer_id */int timer_delete(timer_t *timer_id);/* Setting timer referenced by location timer_id */int timer_settime(timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting);/* Getting time remainning until next expiration*/int timer_gettime(timer_t timer_id, struct itimerspec *expires); int timer_getoverrun(timer_t timer_id);

The API is fully compliant with POSIX standard. Supported clocks areCLOCK_MONOTONIC and CLOCK_REALTIME. A complete description ofPOSIX timers and usage examples can be found in chapter five of the Bill O.Gallmeister book: "POSIX.4 Programming fro the Real World".

3.4) Example

#include <rtl.h>#include <pthread.h>#include <time.h>#include <signal.h>#define MY_SIGNAL RTL_SIGUSR1pthread_t thread;timer_t timer;

#define ONESEC 1000000000LL#define MILISECS_PER_SEC 1000hrtime_t start_time;

void timer_intr(int sig){ rtl_printf("Timer handler called for signal:%d\n",sig); pthread_wakeup_np(pthread_self());

Page 31: WP10 -D10.8 Programmer's Guide - MNIS

}

void *start_routine(void *arg){ struct sched_param p; struct itimerspec new_setting,old_setting,current_timer_specs; struct sigaction sa; long long period= 120LL*ONESEC; hrtime_t now; int signal=MY_SIGNAL; sa.sa_handler=timer_intr; sa.sa_mask=0; sa.sa_flags=0; new_setting.it_interval.tv_sec= 1; new_setting.it_interval.tv_nsec= 0;

new_setting.it_value.tv_sec=1; new_setting.it_value.tv_nsec=start_time;

/* Install the signal handler */ sigaction(signal, &sa, NULL))

/* Arming the timer */ timer_settime(timer[param],0,&new_setting,&old_setting);

/* The period of this thread is 2 minutes!!! */ /* But till will be awaked by the TIMER every second */ pthread_make_periodic_np (pthread_self(), gethrtime(), period );

now=gethrtime(); while (1) { last_expiration=now; now=gethrtime(); timer_gettime(timer[param],&current_timer_specs); rtl_printf("time passed since last expiration:%d (in milis)\n", (int)(now-last_expiration)/MILISECS_PER_SEC); pthread_wait_np(); }}

int init_module(void) { sigevent_t signal;

/* Create the TIMER */ signal.sigev_notify=SIGEV_SIGNAL; signal.sigev_signo=MY_SIGNAL; timer_create(CLOCK_REALTIME,&signal,&(timer[i]));

start_time=ONEMILISEC;

// Threads creation. pthread_create (&thread), NULL, start_routine, (void *) 0); return 0;}

void cleanup_module(void) {

Page 32: WP10 -D10.8 Programmer's Guide - MNIS

pthread_delete_np (thread); timer_delete(timer);}

4) POSIX message queues

4.1) Description

This component implements POSIX message queues facility which can be usedto send messages between RTLinux threads.

UNIX systems offers several possibilities for interprocess communication:signals, pipes and FIFO queues, shared memory, sockets, etc. In RTLinux, themost flexible one is shared memory, but the programmer has to use alternativesynchronisation mechanism to build a safe communication mechanism betweenprocess or threads. On the other hand, signals and pipes lack certain flexibility toestablish communication channels between process. In order to cover some ofthese weaknesses, POSIX standard proposes a message passing facility thatoffers:

Protected and synchronised access to the message queue. Access to datastored in the message queue is properly protected against concurrentoperations.

Prioritised messages. Processes can build several flows over the same queue,and it is ensured that the receiver will pick up the oldest message from the mosturgent flow.

Asynchronous and temporised operation. Threads have not to wait for operationto be finish, i.e., they can send a message without having to wait for someone toread that message. They also can wait an specified amount of time or nothing atall, if the message queue is full or empty.

Asynchronous notification of message arrivals. A receiver thread can configurethe message queue to be notified on message arrivals. That thread can beworking on something else until the expected message arrives.

Page 33: WP10 -D10.8 Programmer's Guide - MNIS

4.2) Usage

This component is compiled as a separate kernel module. In order to use thisfacility you have to select it at the main configuration screen and the compile theRTLinux sources. This facility depends on POSIX signals so you need to selectPOSIX signals in order to enable the message queues selection box.

4.3) Programming interface (API)

This components follows the POSIX API specification for message passingfacility defined in IEEE Std 1003.1-2001. This API also belongs to the OpenGroup Base Specifications Issue 6. The following synopsis presents the list ofsupported message queue functions:

/* Create and destroy message queues */mqd_t mq_open (const char *, int, ...); int mq_unlink (const char *)int mq_close (mqd_t); int mq_getattr (mqd_t, struct mq_attr *); int mq_notify (mqd_t, const struct sigevent *); int mq_setattr (mqd_t, const struct mq_attr *, struct mq_attr *);ssize_t mq_receive (mqd_t, char *, size_t, unsigned *); int mq_send (mqd_t, const char *, size_t, unsigned ); ssize_t mq_timedreceive (mqd_t, char *, size_t, unsigned *, const struct timespec *);int mq_timedsend (mqd_t, const char *, size_t, unsigned, const struct timespec *);

5) Posix Barriers

5.1) Description

Barriers, are defined in the advanced real-time POSIX (IEEE Std 1003.1-2001),as part of the advanced real-time threads extensions. A barrier is a simple andefficient synchronisation utility.

Page 34: WP10 -D10.8 Programmer's Guide - MNIS

These are the steps to create and to use a barrier

1. The barrier attributes are initialized . This is accomplished trough the function pthread_barrierattr_init

2. The barrier is initialized, only once, by calling the function pthread_barrier_init.

This function set the attributes of the barrier (specified in the previous step, orit takes a default attribute object) and the parameter count, which specifies thenumber of threads that are going to synchronise at the barrier.

Although standard posix recommends that the value specified by count mustbe greater than zero, if count is 1, the barrier will not take effect, since noblocking would be produced. Therefore, in this implementation, a value ofcount less or equal than 1 is not valid. Otherwise, EINVAL is returned.

3. When a thread wants to synchronise at the barrier, it calls the functionpthread_barrier_wait .

At this point, the thread will wait until all the rest of the threads have reachedthe same function call. Threads will continue its execution when the lastthread reaches the pthread_barrier_wait function.

4. Finally, both the barrier and the attributes have to be destroyed(pthreadd_barrierattr_destroy and pthread_barrier_destroy).

If there are threads waiting on the barrier, the function pthread_barrier_destroydoes not destroy the barrier, but exits with error EBUSY.

5.2) Usage

To activate the component just mark the option "Posix Barriers in RT-Linux"inside of "Ocera Components Configuration -> Scheduling" in the configurationtool.

This component has no dependencies with other Ocera components or RTLinuxfacilities. Posix Barriers are a high level RTLinux component, since it does notmodify the RTLinux source code, but adds new features. Barriers are notimplemented as a module, it is only necessary to insert the scheduler module(rtl_schedule.o). Barrier functionalities are implemented in two files:rtlinux/schedulers/rtl_barrier.c and rtlinux/include/rtl_barrier.h.

5.3) Programming interface (API)

The API is defined by the POSIX standard. Here is a list of the functions thathave been implemented.

Page 35: WP10 -D10.8 Programmer's Guide - MNIS

a) int pthread_barrierattr_destroy(pthread_barrierattr_t * attr);

The pthread_barrierattr_destroy() function shall destroy a barrier attributesobject. A destroyed attr attributes object can be reinitialized usingpthread_barrierattr_init(); the results of otherwise referencing the object after ithas been destroyed are undefined. An implementation may causepthread_barrierattr_destroy() to set the object referenced by attr to an invalidvalue.

b) int pthread_barrierattr_init(pthread_barrierattr_t * attr );

The pthread_barrierattr_init() function shall initialize a barrier attributes object attrwith the default value for all of the attributes defined by the implementation.Results are undefined if pthread_barrierattr_init() is called specifying an alreadyinitialized attr attributes object.

c) int pthread_barrier_init(pthread_barrier_t * barrier, constpthread_barrierattr_t *attr, unsigned int count );

The pthread_barrier_init() function shall allocate any resources required to usethe barrier referenced by barrier and shall initialize the barrier with attributesreferenced by attr. If attr is NULL, the default barrier attributes shall be used; theeffect is the same as passing the address of a default barrier attributes object.The results are undefined if pthread_barrier_init() is called when any thread isblocked on the barrier (that is, has not returned from the pthread_barrier_wait()call). The results are undefined if a barrier is used without first being initialized.The results are undefined if pthread_barrier_init() is called specifying an alreadyinitialized barrier.

d) int pthread_barrier_destroy( pthread_barrier_t * barrier );

The pthread_barrier_destroy() function shall destroy the barrier referenced bybarrier and release any resources used by the barrier. The effect of subsequentuse of the barrier is undefined until the barrier is reinitialized by another call topthread_barrier_init(). An implementation may use this function to set barrier toan invalid value. The results are undefined if pthread_barrier_destroy() is calledwhen any thread is blocked on the barrier, or if this function is called with anuninitialized barrier.

e) int pthread_barrier_wait( pthread_barrier_t * barrier );

The pthread_barrier_wait() function shall synchronize participating threads at thebarrier referenced by barrier. The calling thread shall block until the requirednumber of threads have called pthread_barrier_wait() specifying the barrier.

Page 36: WP10 -D10.8 Programmer's Guide - MNIS

When the required number of threads have called pthread_barrier_wait()specifying the barrier, the constant PTHREAD_BARRIER_SERIAL_THREADshall be returned to one unspecified thread and zero shall be returned to each ofthe remaining threads. At this point, the barrier shall be reset to the state it hadas a result of the most recent pthread_barrier_init() function that referenced it.

f) int pthread_barrierattr_getpshared( constpthread_barrierattr_t * attr int * pshared );

The pthread_barrierattr_getpshared() function shall obtain the value of theprocess-shared attribute from the attributes object referenced by attr. Thepthread_barrierattr_setpshared() function shall set the process-shared attributein an initialized attributes object referenced by attr. The process-shared attributeis set to PTHREAD_PROCESS_SHARED to permit a barrier to be operatedupon by any thread that has access to the memory where the barrier is allocated.If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, thebarrier shall only be operated upon by threads created within the same processas the thread that initialized the barrier; if threads of different processes attemptto operate on such a barrier, the behavior is undefined.

g) int pthread_barrier_wait( pthread_barrier_t * barrier );

The pthread_barrier_wait() function shall synchronize participating threads at thebarrier referenced by barrier. The calling thread shall block until the requirednumber of threads have called pthread_barrier_wait() specifying the barrier.When the required number of threads have called pthread_barrier_wait()specifying the barrier, the constant PTHREAD_BARRIER_SERIAL_THREADshall be returned to one unspecified thread and zero shall be returned to each ofthe remaining threads. At this point, the barrier shall be reset to the state it hadas a result of the most recent pthread_barrier_init() function that referenced it.

5.4) Example

A barrier can be used to force periodic threads to execute its first activation atthe first time. This example, in this case, will consist of one barrier. Threethreads block on the barrier before becoming periodic. When the last threadarrives to the barrier, then all threads are allowed to continue execution (seeFigure next page).

Page 37: WP10 -D10.8 Programmer's Guide - MNIS

#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <rtl_sched.h>#include <rtl_barrier.h>#include <rtl.h>#include <rtl_time.h>

#define NTASKS 3

pthread_t tasks[NTASKS];hrtime_t now;

pthread_attr_t attrib;struct { int id; int compute; int period;} sched_attrib[NTASKS];

pthread_barrierattr_t barrier_attr;pthread_barrier_t my_barrier;

void * fun(void *arg) {

Page 38: WP10 -D10.8 Programmer's Guide - MNIS

int id = (int)arg;

pthread_barrier_wait(&my_barrier);

pthread_make_periodic_np(pthread_self(), now, sched_attrib[id].period);

while (1){ rtl_delay(sched_attrib[id].compute); pthread_wait_np(); fin--; } pthread_exit(0); return (void *)0;}

int init_module(void){ int x;

sched_attrib[0].compute=1000; sched_attrib[0].period=100000; sched_attrib[1].compute=1900; sched_attrib[1].period=170000; sched_attrib[2].compute=25000; sched_attrib[2].period=200000;

now = gethrtime();

//Initialize the barrier pthread_barrierattr_init(&barrier_attr);

pthread_barrier_init(&my_barrier, &barrier_attr, NTASKS); //pthread_barrierattr_destroy(&barrier_attr); for (x=0; x<NTASKS; x++) { pthread_attr_init(&attrib); pthread_create(&(tasks[x]), &attrib , fun, (void *)x); } return 0;}

void cleanup_module(void){ int x; for (int x=0; x<NTASKS; x++){ pthread_cancel(tasks[x]); pthread_join(tasks[x],NULL); } pthread_barrier_destroy(&my_barrier);}

Page 39: WP10 -D10.8 Programmer's Guide - MNIS

6) Application-Defined Scheduler

6.1) Description

POSIX-Compatible Application-defined scheduling (ADS) is an applicationprogram interface (API) that enables applications to use application-definedscheduling algorithms in a way compatible with the scheduling model defined inPOSIX. Several application-defined schedulers, implemented as special userthreads, can coexist in the system in a predictable way. This way, users canimplement their own scheduling algorithms that can be ported inmediately toother POSIX compliant RTOS.

6.2) Usage

This facility depends on POSIX signals and POSIX Timers, so you need to selectthem in order to enable the ADS selection box (Figure 6).

Once the sources have been compiled you can create the sources of yourscheduling algorithm. This sources will be compiled as a separate kernelmodule.

6.3) Programming interface (API)

The application defined scheduler facility API is a little more complex than"normal" operating systems services like file management since the ADS has toprovide two different API's. One API for the application scheduler thread andanother API for the application scheduled thread. ADS API has been designed tobe included in the POSIX standard. Following is the list of functions that can beused by scheduler threads:

a) Program scheduling actions ( suspending or activatingthreads)

• int posix_appsched_actions_addactivate (posix_appsched_actions_t *sched_actions, pthread_t thread )

Page 40: WP10 -D10.8 Programmer's Guide - MNIS

• int posix_appsched_actions_addsuspend (posix_appsched_actions_t *sched_actions, pthread_t thread )

• int posix_appsched_actions_addlock (posix_appsched_actions_t *sched_actions, pthread_t thread,const pthread_mutex_t *mutex )

b) Execute Scheduling Actions

• int posix_appsched_execute_actions (const posix_appsched_actions_t *sched_actions, const sigset_t * set, const struct timespec * timeout, structtimespec * current_time, struct posix_appsched_event * event )

c) Getting and setting application scheduled thread's data

• int pthread_remote_setspecific (pthread_key_t key, pthread_t th, void *value)

• void * pthread_remote_getspecific (pthread_key_t key, pthread_t th)

d) Set and get mutex-specific data

• int posix_appsched_mutex_setspecific( pthread_mutex_t * mutex, void *value)

• int posix_appsched_mutex_getspecific (const pthread_mutex_t * mutex,void ** data)

• Scheduling events sets manipulation • int posix_appsched_emptyset (posix_appsched_eventset_t * set, int

posix_appsched_fillset posix_appsched_eventset_t * set )• int posix_appsched_addset(posix_appsched_eventset_t * set, int

appsched_event)• int posix_appsched_delset( posix_appsched_eventset_t * set ,int

appsched_event)• int posix_appsched_ismember(const posix_appsched_eventset_t * set, int

appsched_event)• int posix_appsched_seteventmask (const posix_appsched_eventset_t *

set, int posix_appsched_geteventmask, posix_appsched_eventset_t * set )

While in the application scheduled thread's side the API is:

e) Explicit scheduler invocation

• int posix_appsched_invoke_scheduler(void * msg, size_t msg_size) • Manipulate application scheduled threads attributes• int pthread_attr_setthread_type (pthread_attr_t * attr, int type, int

pthread_attr_setappscheduler, pthread_attr_t * attr, pthread_t sched)• int pthread_attr_setappsched_param(pthread_attr_t * attr, void * param, int

size)• int pthread_attr_getappscheduler (pthread_attr_t * attr, pthread_t sched)• int pthread_getappsched_param (pthread_attr_t * attr, pthread_t * sched,

void * param, int * size)

Page 41: WP10 -D10.8 Programmer's Guide - MNIS

f) Application-defined Mutex Protocol

• int pthread_mutexattr_setappscheduler (pthread_mutexattr_t * attr, structrtl_thread_struct * appscheduler)

• int pthread_mutexattr_getappscheduler (const pthread_mutexattr_t * attr,struct rtl_thread_struct * appscheduler)

• int pthread_mutexattr_setappschedparam (pthread_mutexattr_t * attr,const struct pthread_mutex_schedparam * sched_param)

• int pthread_mutexattr_getappschedparam (const pthread_mutexattr_t *attr, struct pthread_mutex_schedparam * sched_param)

• int pthread_mutex_setappschedparam (pthread_mutex_t * mutex, conststruct pthread_mutex_schedparam * sched_param)

• int pthread_mutex_getappschedparam (const pthread_mutex_t * mutex,struct pthread_mutex_schedparam * sched_param)

6.4) Example

This example creates a scheduler thread and two scheduled threads. Thescheduler thread controls the execution of its scheduled threads following aEarliest Deadline First priority assignation. That is, in this example it isimplemented the EDF scheduling algorithm. The scheduled threads are periodicwith deadline equal to period. For each scheduled thread a periodic timer isprogrammed which spires each time the release time is reached. Threads arecreated in the file edf_threads.c. This is the source that will be compiled andinserted as a module. The algorithm is implemented in the files edf_sched.c andedf_sched.h.

/* edf_sched.h*/

#include "../misc/compat.h"#include <rtl_debug.h>#include <time.h>

struct edf_sched_param { struct timespec period;};

#define ERROR(s) {perror (s); rtl_printf("\n"); exit (-1);}//#define ERROR(s) {perror (s); set_break_point_here; exit (-1);}

void *edf_scheduler (void *arg);#define MAX_TASKS 10extern timer_t timer_ids[MAX_TASKS];extern pthread_t tasks[MAX_TASKS];

extern long loops_per_second ;

/* * eat

Page 42: WP10 -D10.8 Programmer's Guide - MNIS

* * Executes during the interval of time 'For_Seconds' */extern inline void eat (float for_seconds){ long num_loop = (long)(loops_per_second * (float)for_seconds); long j = 1; long i; for (i=1; i<=num_loop; i++) { j++; if (j<i) { j = i-j; } else { j = j-1; } }}

extern inline long subtract (struct timespec *a, struct timespec *b){ long result, nanos;

result = (a->tv_sec - b->tv_sec)*1000000; nanos = (a->tv_nsec - b->tv_nsec)/1000; return (result+nanos);}

/* * adjust * * Measures the CPU speed (to be called before any call to 'eat') */extern inline void adjust (void){ struct timespec initial_time, final_time; long interval; int number_of_tries =0; long adjust_time = 1000000; int max_tries = 6;

do { clock_gettime (CLOCK_REALTIME, &initial_time); eat(((float)adjust_time)/1000000.0); clock_gettime (CLOCK_REALTIME, &final_time); interval = subtract(&final_time,&initial_time); loops_per_second = (long)( (float)loops_per_second*(float)adjust_time/(float)interval); number_of_tries++; } while (number_of_tries<=max_tries && labs(interval-adjust_time)>=adjust_time/50);}

/*edf_sched.c*/

Page 43: WP10 -D10.8 Programmer's Guide - MNIS

#include "edf_sched.h"#include "../misc/timespec_operations.h"#include "../misc/generic_lists.h"#include "../misc/generic_lists_order.h"

typedef enum {ACTIVE, BLOCKED, TIMED} th_state_t;

/* Thread-specific data */typedef struct thread_data { struct thread_data * next; th_state_t th_state; struct timespec period; struct timespec next_deadline; /* absolute time */ int id; timer_t timer_id; pthread_t thread_id;} thread_data_t;

thread_data_t th_data[MAX_TASKS];#define free(ptr) do {} while(0)/* Scheduling algorithm data */list_t RQ = NULL;int threads_count = 0; // to assign a different id to each threadthread_data_t *current_thread = NULL; // thread currently chosen to executepthread_key_t edf_key=0;

/* * more_urgent_than */int more_urgent_than (void *left, void *right){ return smaller_timespec (&((thread_data_t *)left)->next_deadline, &((thread_data_t *)right)->next_deadline);}

/* * schedule_next */void schedule_next (posix_appsched_actions_t *actions){ thread_data_t *most_urgent_thread = head (RQ);

if (most_urgent_thread != current_thread) { if (most_urgent_thread != NULL) { // Activate next thread printf (" Activate:%d ptr:%d\n", most_urgent_thread->id,most_urgent_thread->thread_id); if (posix_appsched_actions_addactivate (actions, most_urgent_thread->thread_id)) ERROR ("posix_appsched_actions_addactivate"); }

if (current_thread != NULL && current_thread->th_state != BLOCKED) { // Suspend "old" current thread printf (" Suspend:%d ptr:%d\n", current_thread->id,current_thread->thread_id);

Page 44: WP10 -D10.8 Programmer's Guide - MNIS

if (posix_appsched_actions_addsuspend (actions, current_thread->thread_id)) perror ("posix_appsched_actions_addsuspend"); }

current_thread = most_urgent_thread; }}

/* * add_to_list_of_threads */void add_to_list_of_threads (pthread_t thread_id, const struct timespec *now){ struct edf_sched_param param; thread_data_t *t_data; struct itimerspec timer_prog;

if (pthread_getappschedparam (thread_id,(void *)&param,NULL)) ERROR ("pthread_getschedparam"); t_data = &th_data[threads_count]; t_data->period = param.period; t_data->th_state = ACTIVE; t_data->id = threads_count++; add_timespec (&t_data->next_deadline, now, &t_data->period); t_data->thread_id = thread_id; t_data->timer_id =timer_ids[t_data->id];

// Add to ready queue enqueue_in_order (t_data, &RQ, more_urgent_than); // Assign thread-specific data if (pthread_remote_setspecific (edf_key, thread_id, t_data)) ERROR ("pthread_remote_setspecific"); // Program periodic timer (period = t_data->period) timer_prog.it_value = t_data->next_deadline; timer_prog.it_interval = t_data->period; if (timer_settime (t_data->timer_id, TIMER_ABSTIME, &timer_prog, NULL)) ERROR ("timer_settime");

printf (" Add new thread:%d, period:%ds%dns\n", t_data->id, t_data->period.tv_sec, t_data->period.tv_nsec);}

/* * eliminate_from_list_of_threads */void eliminate_from_list_of_threads (pthread_t thread_id){ thread_data_t *t_data; struct itimerspec null_ts={{0, 0},{0, 0}}; // get thread-specific data if (!(t_data = pthread_remote_getspecific (edf_key, thread_id))) ERROR ("pthread_remote_getspecific"); // disarm timer.

Page 45: WP10 -D10.8 Programmer's Guide - MNIS

timer_settime(t_data->timer_id,0,&null_ts,NULL);

// Remove from scheduling algorithm lists if (t_data->th_state == ACTIVE) dequeue (t_data, &RQ); // Free used memory free (t_data);}

/* * make_ready */void make_ready (pthread_t thread_id, const struct timespec *now){ thread_data_t *t_data; struct itimerspec timer_prog; // get thread-specific data if (!(t_data = pthread_remote_getspecific (edf_key, thread_id))) ERROR ("pthread_remote_getspecific"); t_data->th_state = ACTIVE;

add_timespec (&t_data->next_deadline, now, &t_data->period);

// Program periodic timer timer_prog.it_value = t_data->next_deadline; timer_prog.it_interval = t_data->period; timer_settime (t_data->timer_id, TIMER_ABSTIME, &timer_prog, NULL);}

/* * make_blocked */void make_blocked (pthread_t thread_id){ thread_data_t *t_data; struct itimerspec null_timer_prog = {{0, 0},{0, 0}}; // get thread-specific data if (!(t_data = pthread_remote_getspecific (edf_key, thread_id))) ERROR ("pthread_remote_getspecific"); t_data->th_state = BLOCKED; timer_settime (t_data->timer_id, 0, &null_timer_prog, NULL);}

/* * reached_activation_time */void reached_activation_time (thread_data_t *t_data){ switch (t_data->th_state) { case TIMED: t_data->th_state = ACTIVE; enqueue_in_order (t_data, &RQ, more_urgent_than); incr_timespec (&t_data->next_deadline, &t_data->period); break; case BLOCKED:

Page 46: WP10 -D10.8 Programmer's Guide - MNIS

break; case ACTIVE: // Deadline missed printf (" Deadline missed in thread:%d !!\n", t_data->id); incr_timespec (&t_data->next_deadline, &t_data->period); break; default: printf (" Invalid state:%d in thread:%d !!\n", t_data->th_state, t_data->id); }

// This is only, for debbuging purposes in RTLinux. rt_print_edf_request(events,t_data,FIFO); }

/* * make_timed */void make_timed (pthread_t thread_id){ thread_data_t *t_data; // get thread-specific data if (!(t_data = pthread_remote_getspecific (edf_key, thread_id))) ERROR ("pthread_remote_getspecific"); t_data->th_state = TIMED;

// remove the thread from the ready queue dequeue (t_data, &RQ); }

/* * EDF scheduler thread */void *edf_scheduler (void *arg){ posix_appsched_actions_t actions; struct posix_appsched_event event; sigset_t waited_signal_set; struct timespec now; int i; // Initialize the 'waited_signal_set' sigemptyset (&waited_signal_set); for (i=0;i<MAX_TASKS;i++) sigaddset (&waited_signal_set, (SIGUSR1+i));

// Create a thread-specific data key if (pthread_key_create (&edf_key, NULL)) ERROR ("pthread_create_key");

// Initialize actions object if (posix_appsched_actions_init (&actions)) ERROR ("posix_appsched_actions_init");

while (1) { /* Actions of activation and suspension of threads */ schedule_next (&actions);

Page 47: WP10 -D10.8 Programmer's Guide - MNIS

/* Execute scheduling actions */ if (posix_appsched_execute_actions (&actions,&waited_signal_set, NULL, &now, &event)) ERROR ("posix_appsched_execute_actions");

/* Initialize actions object */ if (posix_appsched_actions_destroy (&actions)) ERROR ("posix_appsched_actions_destroy"); if (posix_appsched_actions_init (&actions)) ERROR ("posix_appsched_actions_init"); /* Process scheduling events */ printf ("\nEvent: %d\n", event.event_code); switch (event.event_code) {

case POSIX_APPSCHED_NEW: add_to_list_of_threads (event.thread, &now); break;

case POSIX_APPSCHED_TERMINATE: eliminate_from_list_of_threads (event.thread); break;

case POSIX_APPSCHED_READY: make_ready (event.thread, &now); break;

case POSIX_APPSCHED_BLOCK: make_blocked (event.thread); break;

case POSIX_APPSCHED_EXPLICIT_CALL: rtl_printf("EXPLICIT_CALL: %d ptr:%d\n",event.thread->user[0]-2,event.thread); // The thread has done all its work for the present activation make_timed (event.thread); break;

case POSIX_APPSCHED_SIGNAL: rtl_printf("SIGNAL %d\n",event.event_info.siginfo.si_signo-SIGUSR1); // This is a trick, since in RTLinux we don't have REAL TIME SIGNALS, yet. reached_activation_time(&th_data[event.event_info.siginfo.si_signo-SIGUSR1]); } }

return NULL;}

/*edf_threads.c*/

#include "edf_sched.h"#include <pthread.h>

#define NTASKS 2timer_t timer_ids[MAX_TASKS];

Page 48: WP10 -D10.8 Programmer's Guide - MNIS

pthread_t sched, tasks[MAX_TASKS];#define MAIN_PRIO MAX_TASKS

long loops_per_second = 30000;

/* Scheduled thread */void * periodic (void * arg){ float amount_of_work = *(float *) arg; int count=0;

posix_appsched_invoke_scheduler (NULL, 0); while (count++<10000) { /* do useful work */ rtl_printf("I am here id:%d, iter:%d\n",pthread_self()->user[0]-2,count); eat (amount_of_work);

rtl_printf("th :%d about to invoke_scheduler\n",pthread_self()->user[0]-2,count); posix_appsched_invoke_scheduler (NULL, 0); }}

int init_module(void){ pthread_attr_t attr; struct edf_sched_param user_param; struct sched_param param; float load1, load2; struct sigevent evp; int ret=0;

adjust (); /* Creation of the scheduler thread */ pthread_attr_init (&attr); param.sched_priority = MAIN_PRIO - 1; if ((ret=pthread_attr_setappschedulerstate(&attr,PTHREAD_APPSCHEDULER))<0) printk("error while pthread_attr_setappschedulerstate(&attr,PTHREAD_APPSCHEDULER)\n"); if (pthread_attr_setschedparam (&attr, &param)) ERROR ("pthread_attr_setschedparam scheduler"); if (pthread_create (&sched, &attr, edf_scheduler, NULL)) ERROR ("pthread_create scheduler");

/* Set main task base priority */ param.sched_priority = MAIN_PRIO; if (pthread_setschedparam (sched, SCHED_FIFO, &param)) perror ("pthread_setschedparam");

pthread_attr_destroy(&attr);

/* Creation of one scheduled thread */ pthread_attr_init (&attr); attr.initial_state=0;

Page 49: WP10 -D10.8 Programmer's Guide - MNIS

pthread_attr_setfp_np(&attr, 1); param.sched_priority = MAIN_PRIO - 3; user_param.period.tv_sec = 0; user_param.period.tv_nsec = 20*1000*1000; // period = 20 ms load1 = 0.001; // load = 1 ms

/* param.posix_appscheduler = sched; param.posix_appsched_param = (void *) &user_param; param.posix_appsched_paramsize = sizeof (struct edf_sched_param); */ evp.sigev_notify = SIGEV_SIGNAL; evp.sigev_signo = SIGUSR1; if (timer_create (CLOCK_REALTIME, &evp,&timer_ids[evp.sigev_signo-SIGUSR1])) ERROR ("timer_create");

if ((ret=pthread_attr_setappschedulerstate(&attr,PTHREAD_REGULAR))<0) printk("error while pthread_attr_setappschedulerstate\n");

if ((ret=pthread_attr_setappschedparam(&attr,(void *) &user_param,sizeof(user_param))<0)) printk("error while pthread_attr_setappschedparam\n");

if (pthread_attr_setappscheduler (&attr, sched)) ERROR ("pthread_attr_setappscheduler 1");

if (pthread_attr_setschedparam (&attr, &param)) ERROR ("pthread_attr_setschedparam 1");

if (pthread_create (&tasks[0], &attr, periodic, &load1)) ERROR ("pthread_create 1");

/* Creation of other scheduled thread */ pthread_attr_init (&attr); attr.initial_state=0; pthread_attr_setfp_np(&attr, 1); param.sched_priority = MAIN_PRIO - 1; user_param.period.tv_sec = 0; user_param.period.tv_nsec = 50*1000*1000;// period = 50 ms load2 = 0.005; // load = 5 ms /* param.posix_appsched_param = (void *) &user_param; param.posix_appsched_paramsize = sizeof (struct edf_sched_param); */ evp.sigev_notify = SIGEV_SIGNAL; evp.sigev_signo = SIGUSR1+1; if (timer_create (CLOCK_REALTIME, &evp,&timer_ids[evp.sigev_signo-SIGUSR1])) ERROR ("timer_create"); if ((ret=pthread_attr_setappschedulerstate(&attr,PTHREAD_REGULAR))<0) printk("error while pthread_attr_setappschedulerstate\n");

if ((ret=pthread_attr_setappschedparam(&attr,(void *) &user_param,sizeof(user_param))<0)) ERROR ("pthread_attr_setappschedparam 2"); if (pthread_attr_setappscheduler (&attr, sched)) ERROR ("pthread_attr_setappscheduler 2");

Page 50: WP10 -D10.8 Programmer's Guide - MNIS

if (pthread_attr_setschedparam (&attr, &param)) ERROR ("pthread_attr_setschedparam 2");

if (pthread_create (&tasks[1], &attr, periodic, &load2)) ERROR ("pthread_create 2"); return 0;}

void cleanup_module(void){ int i; // Remove scheduled threads. for (i=0;i<NTASKS;i++){ timer_delete(timer_ids[i]); pthread_delete_np(tasks[i]); } // Remove Application scheduler thread. pthread_delete_np(sched);

}

7) Ada Support

7.1) Description

This component is a porting of the Gnat compiler run time support to theRTLinux executive. With this porting it is possible to use the ADA language toprogram hard real-time applications in RTLinux. Ada is a standard programming language that was designed with a specialemphasis on real-time and embedded systems programming, also coveringother parts of modern programming such as distributed systems, systemsprogramming, object oriented programming or information systems.

Page 51: WP10 -D10.8 Programmer's Guide - MNIS

7.2) Usage

The Gnat porting is a complex component that modifies the some scripts of theinstalled Gnat compiler code. The ported Gnat run time support runs on top ofthe RTLinux, and use the RTLinux API as a "normal" RTLinux application. Thatis, it neither modifies the OCERA-RTLinux code nor add any new file. For thisreason it has not been integrated into the OCERA framework but has to beinstalled separately. Although not necessary, it is convenient to have experience using Gnat thecompiler before installing RTLGnat.

Next are the installation steps to install RTLGnat (Version 1.0) in the Gnatsystem (assuming that the running Linux kernel and RTLinux executive are theone of the OCERA framework):

1.Please, be sure that you have the original GNAT compiler distributed by ACT(ftp://cs.nyu.edu/pub/gnat/), and REMOVE any other gnat included in your Linuxdistribution. Otherwise, broken executables and libraries can be generated.

2.Select, at least, the following options in the main OCERA config tool:1.RTLinux Configuration -> Priority inheritance (POSIX Priority Protection) 2.RTLinux Configuration -> Floating point support3.OCERA Component Conf. -> Scheduling -> Dynamic memorymanager...4.OCERA Component Conf. -> Scheduling -> POSIX Signals ...5.OCERA Component Conf. -> Scheduling -> POSIX Trace(recommended)

3.Edit the (RTLGnat)/Makefile and modify the path variables to point to the rightdirectories. Among others, the GNAT_PATH variable is the location of the gnatcompiler and libraries, which usually is /usr/gnat

4.Make sure that the proper version of gnat is at the beginning of the PATHvariable, for example: export PATH=/usr/gnat/bin:$PATH

5.You may need root privileges (write access to the GNAT directory) to compileRTLGnat because it will add some files to the standard GNAT distribution.

6.Compile RTLGnat by running "make" from the (RTLGnat) directory.

7.Now RTLGnat has been installed and compiled jointly with the standard Gnatdistribution. You can find the RTLGnat examples in $GNAT_PATH/rtl_examples(usually at /usr/gnat/rtl_examples). To compile the examples, just run "make"from the mentioned directory.

Page 52: WP10 -D10.8 Programmer's Guide - MNIS

RTLGnat will be installed in the directory where GNAT is already installed. Themodifications to the GNAT installation will include a directory called rts-rtlinux,where the needed libraries will be located, and the executables rtlgnatmake,rtload and rtunload. The "rtlgnatmake" script is the equivalent to "gnatmake" in GNAT for Linux.Simply run:

# rtlgnatmake my_app.adb

to obtain the application module "my_app"Once you have created your application object module, RTLinux needs to beloaded in order to run your application:

# rtlinux start

Now you should start up your application by doing:

# rtload my_app

To terminate and remove your running application just run:

# rtunload my_app

7.3) Example

Following example makes use of the POSIX trace component to withAda.Real_Time;

use Ada.Real_Time;with RTL_Pt1;use RTL_Pt1;

procedure Tasks is

task type Std_Task (Id : Integer) is pragma Priority(Id); entry Call; end Std_Task;

task body Std_Task is Next_Time : Time; Period : Time_Span := Microseconds (100); Next_While : Time; Period_While : Time_Span := Microseconds (10); begin

Page 53: WP10 -D10.8 Programmer's Guide - MNIS

accept Call; Next_Time := Clock + Period; loop -- Put ("I am "); Put (Id); New_Line; Next_While := Clock + Period_While; while Next_While > Clock loop null; end loop; delay until Next_Time; Next_Time := Clock + Period; end loop; end Std_Task;

Std_Task1 : Std_Task(1); Std_Task2 : Std_Task(2); dev : Integer;begin-- Std_Task1.Call; dev := Integer(rtl_ktrace_start); Std_Task1.Call; Std_Task2.Call; delay 0.005; dev := Integer(rtl_ktrace_stop);-- Std_Task2.Call;end Tasks;

Page 54: WP10 -D10.8 Programmer's Guide - MNIS

8) POSIX tracing

8.1) Description

As realtime applications become bigger and more complex, the availability ofevent tracing mechanisms becomes more important in order to performdebugging and runtime monitoring. Recently, IEEE has incorporated tracing tothe facilities defined by the POSIX® standard. The result is called the POSIXTrace standard. Tracing can be defined as the combination of two activities: thegeneration of tracing information by a running process, and the collection of thisinformation in order to be analysed. The tracing facility plays an important role inthe OCERA architecture. Besides its primary use as a debugging and tuning tool,the tracing component jointly with the application-defined scheduler componentconstitute the key tools for building fault-tolerance mechanisms. The POSIX trace standard was firstly approved as the amendment 1003.1q ofthe POSIX 1003.1-1996 standard, and then integrated in the most recent versionof POSIX, called 1003.1-2001. Considering that the Trace standard is quiterecent, the reader may not be familiar with its concepts and terminology. Thefollowing sections provide an introduction to the concepts and the structure ofthe tracing system.

8.2) Main concepts

The POSIX Trace standard is founded on two main data types (trace event andtrace stream) and is also based on three different roles which are played duringthe tracing activity: the trace controller process (the process who sets the tracingsystem up), the traced or target process (the process which is actually beingtraced), and the trace analyser process (the process who retrieves the tracinginformation in order to analyse it). All these concepts are detailed in the followingsections.

Page 55: WP10 -D10.8 Programmer's Guide - MNIS

8.3) Data types

a) Trace Event

When a program needs to be traced, it has to generate some information eachtime it reaches "a significant step" (certain instruction in the program s sourcecode). In the POSIX Trace standard terminology, this step is called a trace point,and the tracing information which is generated at that point is called a traceevent. A program containing one or more of this trace points is namedinstrumented application.

A trace event can be thus defined as a data object representing an action whichis executed by either a running process or by the operating system. In thissense, there are two classes of trace events: user trace events, which areexplicitly generated by an instrumented application, and system trace events,which are generated by the operating system1.

Any trace event, being either system or user, belongs to a certain trace eventtype (an internal identifier, of type trace_event_id_t) and it is associated with atrace event name (a human-readable string). For system events, the definition ofevent types and the mapping between these types and their correspondingnames is hard-coded in the implementation of the trace system. Therefore, thisevent types are common for all the instrumented applications and never change(they are always traced). The trace standard predefines some event types, whichare related to the trace system itself, and permits the operating system designerto add some others which may be interesting to that system. The definition ofuser event types is very different. When an instrumented application wants togenerate trace event of a particular type, it has first to create this type. This isdone by invoking a particular function (posix_trace_open()) that, given a newtrace event name, returns a new trace event type; then, events of this type canbe generated from that moment on. If the event name was already registered forthat application, then the previously associated identifier is returned. Themapping between user event types and their names is private to eachinstrumented program and lasts while the program is running.

The generation of a trace event is done internally by the trace system for asystem event and explicitly (by the application when invoking posix_trace_event()) for a user trace event. In both cases, the standard defines that the tracesystem has to store some information for each trace event being generated,including, at least, the following:

a. the trace event type identifier,

b. a timestamp,

c. the process identifier of the traced process (if the event is process-dependent),

d. the thread identifier (of the thread related to the event), if the event isprocess-dependent and the O.S. supports threads,

e. the program address at which the event was generated,

Page 56: WP10 -D10.8 Programmer's Guide - MNIS

f. any extra data that the system or the instrumented application wants toassociate with the event, along with the data size2.

b) Trace Stream

When the system or an application trace an event, all the information related to ithas to be stored somewhere before it can be retrieved, in order to be analyzed.This place is a trace stream. Formally speaking, a trace stream is defined as anon-persistent, internal (opaque) data object containing a sequence of traceevents plus some internal information to interpret those trace events. Thestandard does not define a stream as a persisten object and thus it is assumedto be volatile, that is, to reside in main memory.

The standard establishes that, before any event can be stored for a process, atrace stream has to be explicitly created to trace that particular process (theprocess pid is one of the arguments of the stream creation function). In the mostgeneral case, the relationship between streams and processes is many to many.On the one hand, many processes can be traced in a single stream; in particular,this happens if the target process forks after a stream has been created for the(parent) process. On the other hand, the standard permits that many streams arecreated to trace the same process; if so, each event generated by the process(or by the operating system) is registered in all these streams.

Streams also support filtering. The application can define and apply a filter to atrace stream. Basically, the filter establishes which event types the stream isaccepting (and hence storing) and which are not. Therefore, trace eventscorresponding to types which are filtered out from a certain stream will not bestored in the stream. Each stream in the system(even if associated with thesame process) can potentially be applied a different filter. This filter can beapplied, removed or changed at any time.

The standard defines two classes of trace streams: active and pre-recorded,which are described below.

a. Active trace stream. This is a stream that has been created for tracingevents and has not yet been shut down. This means that it is nowaccepting events to store. An active trace stream can be of two differenttypes, depending on whether it has been created with or without a log. Ina trace stream with log, the stream is created along with a log.

Page 57: WP10 -D10.8 Programmer's Guide - MNIS

A log is a persistent object (that is, a file) in which the events stored in thestream are saved each time the stream is flushed by the trace system.The trace controller process can create such a stream by calling thefunction posix_trace_create_withlog(). Thus, events traced from the targetprocess are stored in the stream until it is flushed, either automatically bythe trace system or when the trace controller process invokes theposix_trace_flush() function. In either case, the flushing then frees theresources previously occupied by the events just written to the log, makingthese resources available for new events to be stored. This is shown inFigure 2-(a). In streams with a log, events are never directly retrieved fromthe stream but from the log (see Pre-recorded trace stream below), oncethe stream has been shut down. That is, the log is not available forretrieving the events until the tracing of events is over. In a trace streamwithout log (created by calling posix_trace_create()), trace events arenever written to any persistent media, but instead they remain in thestream (in memory) until they are explicitly retrieved. Thus, the stream isaccessed concurrently for storing (target process) and retrieving (traceanalyser process) events. These accesses can be done only while thestream is active (that is, before it is shut down) since, after that, all thestream resources are freed. Therefore, an active trace stream without alog is used for on-line analysis of events, as shown in Figure 1.

Page 58: WP10 -D10.8 Programmer's Guide - MNIS

The standard establishes that the trace analyzer process retrieves theevents one by one, with the trace system always reporting the oldeststored event first. When this oldest event has been reported, theresources that it was using in the stream have to be freed and thenbecome available for new events to be traced.

If the rate at which events are being traced is higher than the rate at whichthe trace analyser process is retrieving them from the stream, then thestream may become full. If an active stream without log becomes full, itmay either stop accepting events or loop; this depends on the so calledstream full policy, which is one of its attributes. In the former case, thestream will start accepting events again when a certain amount of eventsin the stream have been retrieved, hence freeing resources for the newones to be stored. In the latter (loop) case, when the stream is full, theoldest recorded events in the stream are lost as new events are stored(that is, the oldest events are overwritten).

Page 59: WP10 -D10.8 Programmer's Guide - MNIS

b. Pre-recorded trace stream. A stream of this class is used for retrievingtrace events which were previously stored in a log. In particular, the log fileis opened into a (pre-recorded) stream from which events are thenretrieved. Thus, off-line analysis of events is performed in two steps: first,events are traced into an active stream with log; second, after this streamis shut down, the log can be opened into a pre-recorded stream fromwhich the events are retrieved. This process is shown in Figure 2.

c) Processes Involved in the Tracing Activity

The standard defines that up to three different roles can be played in eachtracing activity: trace controller process, traced (or target) process and traceanalyzer process. In the most general case, each of these roles is executed by aseparate process. However, nothing in the standard prevents from having two (oreven the three) of these roles executed by the same process. In a small, multi-threaded application, we can have, for example, the three roles played bydifferent threads inside the same process. These roles are now explained indetail.

d) Trace Controller Process

The trace controller process is the process that sets the tracing system up inorder to trace a (target) process, which can be the same process or a differentone. In particular, this process is in charge of, at least, the following actions:

a. Creating a trace stream with its particular attributes (e.g, if the stream iswith or without a log, the stream full policy, etc.). This is further detailedbelow.

b. Starting and stopping tracing when necessary. This is done by callingposix_trace_start() and posix_trace_stop(), respectively. Each activestream can be in two different states: running or suspended. These twostates determine whether or not the stream is accepting events to bestored. The trace controller process can start and stop the stream asmany times as it wants. If the stream full policy is to trace until full(POSIX_TRACE_UNTIL_FULL), the trace system will automatically stopthe stream when full and start it again when some (or all) of its storedevents have been retrieved.

c. Filtering the types of events to be traced. Each stream is initially createdwith an empty filter (that is, without filtering any event type). If this is notthe required behaviour, the trace controller process can build a set ofevent types (trace_event_set_t), include the appropriate event types in it,and apply it as a filter to the stream (by invoking posix_trace_set_filter()).After that, the stream will reject any event whose type is in the filter set.

Page 60: WP10 -D10.8 Programmer's Guide - MNIS

d. Shutting the stream down, when the tracing is over(posix_trace_shutdown()). The standard requires that shutting a streamdown must free all the stream resources. That is, the stream is destroyedand no more operations can be done on it.

Among all these basic actions, the creation of the stream is the most complexone. This action is done in two steps:

1. Create a stream attribute object (trace_attr_t) and set each of its attributesappropriately. Since this type is also opaque to the user (that is, internal to thetrace system), the standard provides a function to initialize an attribute objectand then pairs of functions to get and set each of the individual attributesincluded in the object. Some of these attributes are: the stream name, thestream minimum size, the event data maximum size, the stream full policy,etc. This setting up is performed before invoking the call to create the stream.

2. Create the stream (trace_id_t). There are two different functions to create anactive stream, depending on whether it has to be with or without a log.Respectively, these functions are posix_trace_create_withlog() andposix_trace_create(). In either case, the arguments of the creation functionare the stream attribute object, previously initialised and set (see above), andthe target process pid (process identifier). The main implication of this is thatthe target process has to exist before the trace controller process can create astream to trace it. Besides, it has to have enough privileges over the target todo it. The exact definition of this latter requirement depends on theimplementation of the trace system. The stream identifier returned in thisfunction can only be used by the process that has created the stream. Onlythis process can thus directly access the stream in any way. This establishessome limitations that will be commented below.

Optionally, the trace controller process can also perform other actions on thestream, once the stream has been created:

Clearing the stream (posix_trace_clear()). This clears all the events that are nowin the stream, but leaves its behaviour (attributes) intact. Clearing the streammakes it exactly in the same state that it was just after being created.

Flushing the stream (posix_trace_flush()). If the stream is created with a log, thisaction produces an automatic flushing of all the events which are now in thestream to the log. Otherwise, an error is returned.

Querying the stream attributes (posix_trace_get_attr()) and the stream currentstatus (posix_trace_get_status()). The stream status includes whether thestream is currently running or suspended, whether or not an overrun hasoccurred, etc.

Page 61: WP10 -D10.8 Programmer's Guide - MNIS

Retrieving the list of event types defined for the stream. The list is retrieved inorder, since the function posix_trace_eventtypelist_getnext_id() returns the firstevent type when it is invoked for the first time, and the next event type insubsequent calls. At any time, the retrieval of event types can be initialised bycalling posix_trace_eventtypelist rewind(). Actually, the standard establishes thatthe event types are not actually associated with a particular stream, but to aparticular target process. In other words, the list of event types is the same for allthe streams which are tracing the same target.

Mapping event names to event types (posix_trace_trid_eventid_open()). This isnormally performed by the target process in order to create its own user eventtypes. However, the trace controller process can use the mapping function in theopposite way: given a well-known user trace event name, the mapping functionwill return the event type identifier; then, the trace controller process can use thatidentifier to set up a stream filter, for example.

e) The Traced or Target Process

The traced or target process is the process that is being traced, that is, is theprocess for which a trace stream has been created and set up. According to thestandard, only two functions can actually be called from a target process:

a. A function to register a new user event type for this process(posix_trace_eventid_open()). The input argument of this function is the(new) event type name. If this name has already being registered for thattarget, then the previously mapped event type identifier is returned. If not,then a new identifier is internally associated with this name and returned.If an implementation defined maximum amount of user event types hadalready been registered for that target process, then a predefined eventtype called POSIX TRACE_UNNAMED_USEREVENT is returned. Ifsuccessful, this registration is valid for all the streams that have beencreated, or will be created, to trace the target process (even if no streamhas still been created for that target). From the user viewpoint, therefore,the identification of user event types is done in a per-name basis (insteadof using integer values, for example). This allows for a name space wideenough to avoid collisions when independent pieces of instrumented codeare linked together into a single application. This include, for example, thecase of linking an instrumented third-party library to our code, even whenwe do not have the library s source code.

b. A function to trace an event (posix_trace_event()). This function has threeinput arguments: the event type, which must have been previouslyregistered (see above), a pointer to any extra data that has to be storedalong with the event, and the size of this data3. The event is stored in allthe streams created for that particular target which are currently runningand which do not have the event s type being filtered out.

Page 62: WP10 -D10.8 Programmer's Guide - MNIS

It is important to point out that neither of these functions accepts a streamidentifier as a parameter. That is, according to the standard philosophy, thetarget is programmed to invoke these functions without being aware (andindependently) of actually being traced or not. The result is that calling theposix_trace_event() function has no effect if no stream has been created for thetarget. In other words, an instrumented running program does not actuallybecome a target process until at least one stream has been created for it. Thecase of the posix_trace_eventid_open() function is different since, as explainedabove, the trace system will register any new event type for the program evenwhen no stream has been created for tracing the process.

This philosophy completely decouples the target from the trace controllerprocess, with many interesting advantages. For example, imagine an applicationthat runs for long periods of time without stop (a real-time application or adatabase, for instance). It may be interesting to know, every once in a while, howthis application is performing. Therefore, this (instrumented) application can bethe target of an inspector (trace controller) program that, periodically, createsone or more streams to trace it, gets the resulting events, and then destroys thestream(s). Depending on the application characteristics, this occasional tracingmay be good enough to check how the application is behaving, and does notoverload the system with a continuous tracing.

f) Trace Analyser Process

This process is in charge of retrieving the stored events in order to analyse them.The standard defines three alternative retrieval functions to be used by the traceanalyser process:

a. posix_trace_getnext_event(). This function retrieves one event from thestream whose identifier is provided as a parameter. If no event isimmediately available, the function blocks the invoking process (or thread)until an event is available.

b. posix_trace_timedgetnext_event(). This function works in a similar fashionthan the previous one, but, when no event is immediately available, itblocks the process until either an event is available or an absolute timeoutis reached (whatever of both happens first). If the timeout is producedfirst, the invoking process gets the corresponding error code.

c. posix_trace_trygetnext_event(). This function never blocks the invokingprocess: it either return a retrieved event or an error code, if no event isavailable at the moment.

If successful, any of these functions retrieve the oldest event stored in thestream which has not still been reported. The age of each event is calculatedaccording to the automatic timestamp performed by the trace system when theevent is recorded.

Page 63: WP10 -D10.8 Programmer's Guide - MNIS

As explained above, the events can be only be retrieved from two differentplaces: (1) from an active stream without log; (2) from the log of a (previouslydestroyed) stream with log, once this log has been opened into a (pre-recorded)trace stream. This defines the two kinds of analysis that the standard supports:

a. a)On-line analysis. In this kind of analysis, the trace analyzer processretrieves the events from an active trace stream (without log). As statedabove, the retrieval function (any of them) needs to provide the stream sidentifier; however, according to the standard, this identifier can only beused within the process that created the stream. This forces that, in an on-line analysis, the trace analyzer process and the trace controller processhave to be the same one.

b. Off-line analysis. As explained in Trace Controller Process subsection,this analysis is done in two steps: in the first step, events are recorded intoan active trace stream with log that, automatically or under request of thetrace controller process, flushes these events to the log (file). Once thisstep is over, the trace analyser process opens the log into a private, pre-recorded stream (posix_trace_open()), from which it can start retrievingthe events. Only the first of the three retrieval functions mentioned abovecan actually be used in a pre-recorded stream. Obviously, in this case,this function will never make the trace analyser process to block, since allthe events are already stored in the stream. From a pre-recorded stream,events are always reported in order (according to the recordingtimestamp) but they are not erased from the stream after being retrieved.If necessary, the trace analyser process can start retrieving the eventsagain from the oldest one by rewinding the stream (posix_trace_rewind()),without having to re-open the log.

In addition, the trace analyser process can also retrieve other information of thestream (either active or pre-recorded), including the list of registered event typesand its names, the stream attribute object (and then each of its individualattributes), the stream current status (for an active stream), etc. All thisinformation is intended to make the trace analyser process able to correctlyinterpret the trace events which it is retrieving.

8.4) Additional information

Since this part of the POSIX standard was published recently, there is still a lackof documentation in the printed form (as fas as the authors know there is not abook that covers this issues of the PSOXI standard), also the implementationdone in OCERA was one of the first implementations of the standard. For moreinformation the reader is referred to the online rationale and man pages availableat the OpenGroup site: http://www.opengroup.org/onlinepubs/007904975/.

Page 64: WP10 -D10.8 Programmer's Guide - MNIS

8.5) Example

The following example creates three new user event types and a trace stream,and then starts five RTLinux threads. Among them, three periodically executeand just consume CPU, another one periodically wakes up and trace theseevents, and the last one waits until a new event is available and then retrieves itand writes its contents to the console.

#include <rtl.h>#include <time.h>#include <pthread.h>#include <rtl_sched.h>#include <trace.h>#include <rtl_ktrace.h>

static trace_id_t trid;static trace_event_id_t ev_char, ev_int, ev_string;static pthread_t thr1, thr2, thr3, thr4, thr5;

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/***********************************************************/void *writer(void *dummy) { int i, j, k; char s[164] ="hello world!hello world!hello world!hello world!hello world!hello world!helloworld!hello world!hello world!hello world!hello world!hello world!hello world!\0"; char c; void *data;

// Create a new event type: posix_trace_eventid_open ("user event string", &ev_string); c = 'A'; k = 0;

pthread_wait_np();

for (i=0; i<10; i++) { for (j=0; j<700000; j++);

pthread_mutex_lock(&mutex); data = (void *) & c; posix_trace_event(ev_char, data, sizeof(char)); data = (void *) & k; posix_trace_event(ev_int, data, sizeof(int));

for (j=0; j<70000; j++);

posix_trace_event(ev_string, s, sizeof(s));

// Values for next loop: c += 1; k += 1;

Page 65: WP10 -D10.8 Programmer's Guide - MNIS

pthread_mutex_unlock(&mutex); pthread_wait_np(); } return (void *) 0;}

/***********************************************************/void *just_execute(void *loops) { int i, j, nloops = (int) loops;

for (i=0; i<100; i++) { for (j=0; j<nloops/4; j++); pthread_mutex_lock(&mutex); for (j=0; j<nloops/2; j++); pthread_mutex_unlock(&mutex); for (j=0; j<nloops/4; j++);

pthread_wait_np(); }

return (void *) 0;}

/***********************************************************/void *reader(void *loops) { int error; trace_attr_t trace_attr; char str[TRACE_NAME_MAX]; struct posix_trace_event_info event; char data[64]; size_t datalen; int unavailable; int *ent; char *car; trace_event_id_t evid;

error = posix_trace_get_attr(trid, &trace_attr); rtl_printf("get attr (%d)\n", error); error = posix_trace_attr_getgenversion(&trace_attr, str); rtl_printf( "get genversion (%d): %s\n", error, str);

posix_trace_eventtypelist_rewind(trid); posix_trace_eventtypelist_getnext_id (trid, &evid, &unavailable); while (! unavailable) { posix_trace_eventid_get_name (trid, evid, str); rtl_printf("Event %d name %s\n", evid, str); posix_trace_eventtypelist_getnext_id (trid, &evid, &unavailable); }

error = 0; unavailable = 0;

while (! error && ! unavailable) {

event.posix_event_id = 1024; error = posix_trace_getnext_event(trid,

Page 66: WP10 -D10.8 Programmer's Guide - MNIS

&event, &data, sizeof(data), &datalen, &unavailable); if(error) { rtl_printf("No more events (%d). Exiting\n", error);

} else if (unavailable) { rtl_printf( " Event unavailable\n");

} else { posix_trace_eventid_get_name (trid, event.posix_event_id, str);

// Now switch depending on the event type (name): if (!strcmp(str,"user event char")) { car = (char *) data; rtl_printf( " Time =%ld.%ld. Event %d (%s) with data=%c (size = %d)\n", event.posix_timestamp.tv_sec, event.posix_timestamp.tv_nsec, event.posix_event_id, str, *car, datalen); } else if (!strcmp(str,"user event int")) { ent = (int *) data; rtl_printf( " Time =%ld.%ld. Event %d (%s) with data=%d (size = %d)\n", event.posix_timestamp.tv_sec, event.posix_timestamp.tv_nsec, event.posix_event_id, str, *ent, datalen); } else if (!strcmp(str,"user event string")) { rtl_printf( " Time =%ld.%ld. Event %d (%s) with data=%s (size = %d)\n", event.posix_timestamp.tv_sec, event.posix_timestamp.tv_nsec, event.posix_event_id, str, (char *) data, datalen); } else { rtl_printf( " Time =%ld.%ld. Event %d (%s) with data unknown\n", event.posix_timestamp.tv_sec, event.posix_timestamp.tv_nsec, event.posix_event_id, str); } } } rtl_printf("Error = %d Unavailble = %d \n", error, unavailable);

return (void *) 0;}

/***********************************************************/int init_module(void) {

trace_attr_t attr; pthread_attr_t thattr; trace_event_set_t set; int error;

// Start the automatic tracing of kernel events: rtl_ktrace_start();

// Create and set the trace attribute:

Page 67: WP10 -D10.8 Programmer's Guide - MNIS

error = posix_trace_attr_init(&attr); error = posix_trace_attr_setstreamfullpolicy (&attr, POSIX_TRACE_UNTIL_FULL); error = posix_trace_attr_setname(&attr, TRACE_STREAM1_NAME); error = posix_trace_attr_setmaxdatasize(&attr, 64); error = posix_trace_attr_setstreamsize(&attr, 4096); // Create the stream: error = posix_trace_create(0, &attr, &trid); if (error) return -1;

// Create new event types associated with this stream: error = posix_trace_trid_eventid_open (trid,"user event char", &ev_char); error = posix_trace_trid_eventid_open (trid,"user event int", &ev_int);

// Set the stream filter to only record user events: posix_trace_eventset_fill(&set, POSIX_TRACE_SYSTEM_EVENTS);

error = posix_trace_set_filter(trid, (const trace_event_set_t *) &set, POSIX_TRACE_SET_EVENTSET);

// Start tracing: error = posix_trace_start(trid); if (error) return -1;

// Create the 'writer' task (the one which traces user events): pthread_attr_init (&thattr); pthread_create (&thr1, &thattr, writer, 0); pthread_make_periodic_np(thr1, 0, (hrtime_t) 400000000);

// Create other tasks which just consume cpu // This one awakes each 20 msec: pthread_create (&thr2, &thattr, just_execute, (void *) 100000); pthread_make_periodic_np(thr2, 0, (hrtime_t) 20000000);

// This one awakes each 25 msec: pthread_create (&thr3, &thattr, just_execute, (void *) 300000); pthread_make_periodic_np(thr3, 0, (hrtime_t) 25000000);

// This one awakes each 50 msec: pthread_create (&thr4, &thattr, just_execute, (void *) 200000); pthread_make_periodic_np(thr4, 0, (hrtime_t) 50000000);

// Create the 'reader' task (awakes only once): pthread_create (&thr5, &thattr, reader, (void *) 200000);

return 0;}

/***********************************************************/void cleanup_module(void) {

rtl_printf("rtl_tasks: CLEANUP!!!\n");

Page 68: WP10 -D10.8 Programmer's Guide - MNIS

// Stop and shutdown the stream: posix_trace_shutdown(trid);

// Delete the tasks: pthread_delete_np(thr1); pthread_delete_np(thr2); pthread_delete_np(thr3); pthread_delete_np(thr4); pthread_delete_np(thr5);

// Stop the tracing of kernel events: rtl_ktrace_stop();}

Page 69: WP10 -D10.8 Programmer's Guide - MNIS

PART IIIPART IIIRTLinux/Linux interface

Driver

Page 70: WP10 -D10.8 Programmer's Guide - MNIS

PART IVPART IVDriver framework

Page 71: WP10 -D10.8 Programmer's Guide - MNIS

V) Driver Framework

By Pierre Morel – MNIS

1) Introduction

Writing drivers for OCERA is special because you do not have a single driverframework but in fact two drivers framework: one for RTLinux-GPL and one forLinux.In this chapter we will focus on RTLinux-GPL drivers. The framework for writingLinux drivers is easy to find on INTERNET.

For example at http://www.xml.com/ldd/chapter/book/

even if it is modified by the RTLinux patch, most of the framework is stillidentical. We will provide a little chapter on the changed induced by the RTLinuxpatch later in the document.

1.1) Dual System aspect

The only new thing to take into account when writing a Linux drivers withRTLinux being running under is RTLinux of course. Two drivers cannot worktogether one in Linux and one in RTLinux, you will have to choose where youhandle the hardware.

Page 72: WP10 -D10.8 Programmer's Guide - MNIS

A second thing you must take care of is that RTLinux installation, as explained ina previous chapter is done by patching the Linux sources. That means that thestandard Linux Driver Framework is slightly modified and if you write a new driveryou cannot use the standard framework because for example you are notallowed to clear interrupts within a Linux driver running above RTLinux.

1.2) Hard real-time aspect

A second aspect is that the Linux drivers do not run with interrupts disabled, theinterrupts are caught by RTLinux and dispatch later, simulating the interruptdisabling for the Linux driver. This increase the interrupt latency for the Linuxdriver. Especially if RTLinux is heavily used.

1.3) Soft real-time aspect

Another aspect of OCERA is the soft real-time at the Linux Level, provided bythe Low Latency patch, the pre-emption patch and the QOS component.

To take good care of the interrupt latency, you will have to write short interruptroutines, making the minimum while interruption are disallowed and passing thehardware management to a tasklet as soon as possible.

Take care of buggy drivers, like most of the serial drivers that call the linediscipline at the interrupt level, increasing strongly the interrupt and systemlatency.

2) Linux Driver framework

The Linux driver framework is somewhat complex in that you have a lot ofpossibilities to handle hardware and a lot of different driver's types, for networks,serial lines, blocks, sound and so on.

There is a lot of documentation on the Linux Driver's Framework.

Page 73: WP10 -D10.8 Programmer's Guide - MNIS

We do not discuss on User level drivers that can be used since the 2.6 Linuxkernel series and available with a patch for the 2.4 series, that is a special case.

We speak only on standard drivers.

Take look at the following drawing:

You see pink blocks representing the hardware, green blocks representingsoftware executable code and blue blocks representing software data.

2.1) A hardware interrupt occurs

When the hardware fires, it starts an interrupt, all interrupts under Linux arehandled by the do_irq function.

This function uses the hw_interrupt_t structure describing the ProgrammableInterrupt Controller to retrieve the appropriate function to handle the firing PIC.

Page 74: WP10 -D10.8 Programmer's Guide - MNIS

Then, according to the interrupt line it follows the irqaction_t list to call theassociated interrupt handler.

The handler is in charge to handle the interruption.

When it finish to handle the hardware interruption, do_irq calls the do_soft_irqfunction that will examine if any soft IRQ is to be handled.

2.2) A software interrupt occurs

Soft interrupt are triggered, as their name let suppose, by software.

They can be set by hardware interrupt handlers to delay operations afterreleasing the interrupt line. Serial lines driver do this to call the line discipline outof the interrupt handler. So do the network drivers to call protocols specificmodules.

The do_soft_irq function look at four queues, a high priority bottom half, BH,queue, a transmit BH queue and a receive BH queue used to handle networkprotocols and a low priority BH queue. The BH on the low priority queue arecalled tasklets.

It is important to remember that soft_irqs are to be handle like normal hardwareIRQ, in that they do not have a task context which means that they are notallowed to sleep or block.

A special BH, executes in the context of keventd. Keventd just provides a contextto the BH.

As do_soft_irq executes without disabling interruptions, it can be that a soft IRQis posted during the loop dispatching the processor to the tasklets. In that case itis not taken in account. To be sure that the tasklet will be called a daemon, theksoftirqd daemon is executed in the kernel space just to call do_soft_irq.

2.3) Conclusion

The Linux driver's framework is not changed by the use of RTLinux.

The rest of the chapter will focus on the RTLinux driver's framework.

Page 75: WP10 -D10.8 Programmer's Guide - MNIS

3) The big Picture

We have inside OCERA two operating systems: a Hard real time operatingsystem, we call RTLinux and a time sharing operating system: Linux.

All these systems running on the same hardware.

First take a look ate the following drawing:

We have in the blue square the low part of the Linux Interrupt Handling drawingwe saw on the last page.

In the yellow square, we have the RTLinux Interrupt Handling scheme:

Page 76: WP10 -D10.8 Programmer's Guide - MNIS

3.1) A hardware Interrupt occurs

When the hardware fires, it starts an interrupt, all interrupts under RTLinux arehandled by the rtl_intercept routine.

The rtl_intercept routine acknowledge the PIC and dispatch the interrupt to theassociated RTLinux handler, retrieving it through an offset in thertl_global_handlers table.

If the interrupt is associated with a Linux handler, the routine calls the Linuxhandler with this interrupt being disabled in software.

So, remember the do_IRQ routine in Linux, the routine is replaced by anothersimilar routine to dispatch the interrupt to the irqaction_t associated list. Then thesystem act as a normal Linux system.

3.2) Lets all work together

Now that we have seen what happen when an interrupt fire, let see how all thedifferent scheduled routines may work together and what are the prioritiesbetween them all, between the both systems and the two drivers architectures.

The following table sort the system and drivers according to their priorities:

Scheduling level Address space have protectionagainst

can activate

Normal process

RT Process

Linux User's space

Normal process,kernel thread

Process

Kernel thread

Soft IRQ Tasklet

Soft IRQ / BH

Linux IRQ handler

RTOS thread

RTOS IRQ handler

Linux Kernel Processes,BH Linux IRQ

Process, Soft IRQ

Process, Soft IRQ

Process, Soft IRQ

Process, Soft IRQ

IRQ RT thread,Linux IRQ, Soft IRQ

In this table, we see that nothing in Linux has protection against RTOS thread orIRQ and that the RTOS can only activate Linux IRQ or Linux soft IRQ.

Page 77: WP10 -D10.8 Programmer's Guide - MNIS

Another point to study now is how do all these scheduling levels synchronize andwhat are the mechanism and functions to protect against and activate otherlevels.

4) Synchronization mechanism

To synchronize the different levels we have at hand the standard synchronizationmechanisms of Linux and RTLinux, semaphores, mutex and spinlock.

We also have the protection mechanisms against interrupts cli, sti and derivativespinlock_irq_save() spinlock_irq_restore().

These functions under Linux when used with RTLinux are changed to be virtualfunctions setting and clearing bits in RTLinux virtual interrupt handling.

This protect the RTOS against setting or clearing interrupts from Linux handlersor from the Linux kernel.

Of course, RTLinux needs to protect some data from being accessed from boththread and interrupt handler unsynchronized and to achieve it RTLinux proposethe real functions: rtl_spinlock_irq_save(), rtl_spinunlock_irqrestore().

4.1) Atomic operations

A set of functions insure atomic operations. A driver may have to use theseatomic operations to be sure that race conditions between two CPU in a multi-CPU environment will not occur.

These atomic operations are hardware design dependant and act on the way theDATA bus between the processor and the memory is locked during a READ-MODIFY-WRITE operation.

It is the lowest possible synchronization mechanism and it can be used for othersynchronization mechanism since it is by construction an un-interruptible way totest and set a shared resource.

Linux atomic operation are:

Page 78: WP10 -D10.8 Programmer's Guide - MNIS

atomic_read(v), atomic_set(v,i),atomic_add(i,v), atomic_sub(i,v), atomic_sub_and_test(i,v), atomic_inc(v), atomic_dec(v), atomic_inc_and_test(v), atomic_dec_and_test(v), atominc_add_negative(i,v)

A set of atomic operations works on bit masks:

test_bit(nr,addr), set_bit(nr,addr), clear_bit(nr,addr), change_bit(nr,addr), test_and_set_bit(nr,addr), test_and_clear_bit(nr,addr), test_and_change_bit(nr,addr), atomic_clear_mask(mask,addr), atomic_set_mask(mask,addr)

4.2) Memory barriers at CPU level

The memory barriers, at CPU level, are different from the memory barrier at thescheduling level, they synchronize the instructions in the processor pipeline toinsure that no instruction placed after the barrier begin to execute before allinstructions placed before the barrier finished.

Of course memory barriers are processor dependant. All atomic instructions act as memory barriers by design1, and Linux providesmacro to implement the barriers:

mb(), rmb(), wmb(), smp_mb(), smp_rmb(), smp_wmb()

1 Because if they do not act as memory barrier, no SMP synchronization would be possible, allprocessors neeed to make these instructions act as memory barriers. Other instructions likeinstructions afecting control registers and iret must also act as memory barriers

Page 79: WP10 -D10.8 Programmer's Guide - MNIS

4.3) Interrupt disabling

a) Mono-processors

Linux provides local_irq_disable() and local_irq_enable() functions to disable andrestore the possibility of interruptions. They act on the processor where theinstruction is executed and in OCERA act only on the virtual interrupts.

RTLinux provides rtl_local_irq_disable() ane rtl_irq_enable() functions toeffectively act on the interrupt authorization.

b) Multi-processor

Some time the system needs to disable all interrupts on all processors to be surethat the access to a device is unique. To do this Linux proposes the cli() macrowhich tries to acquire the global_irq_lock spinlock (see next chapter).

To avoid deadlock conditions, this macro must be called out of any interruptprotected region and waits until all interrupts and bottom halves on all processorfinished before to go on.

RTLinux does not provide global IRQ handling.

4.4) Disabling Soft IRQ

Soft IRQ may be disabled by invoking the local_bh_disable() and respectivelyenabled by the local_bh_enable() macros.

4.5) Spinlocks

Spinlocks are used to synchronize two or more CPU with a busy wait.

Of course setting spin_lock freeze the operating system until the spinlock isunlocked.

It has no meaning to use spinlock in a uni-processor environment outer the factthat doing so will prepare the function using for muti-processing.

Note that with RTLInux spinlocks locked by Linux may be unlock by RTLinux.

Spinlocks lock/unlock are generally combined with IRQ disable/enable becausea lot of regions need to be protected against interrupt and external access.

RTLinux provides the following primitives to handle spinlocks:

rtl_spin_lock_init(), rtl_spinlock(), rtl_spin_unlock(), rtl_spinlock_irqsave(),

Page 80: WP10 -D10.8 Programmer's Guide - MNIS

rtl_spinunlock_irqrestore().

4.6) semaphores

Semaphores are one level higher, it works together with the scheduler tosynchronize the threads.

A thread may acquire and release a semaphore a driver in interrupt handlingmay only release a semaphore as it has no context.

RTLinux provides the following primitives to handle semaphores:

int sem_init(sem_t *sem, int pshared, unsigned int value);int sem_destroy(sem_t *sem);int sem_getvalue(sem_t *sem, int *sval);int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_post(sem_t *sem);int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

4.7) Signaling to Linux with Soft IRQ

RTLinux provides a way to signal events to Linux by sending a soft_irq to Linux:

rtl_get_soft_irq( void (*handler)(int,void*,struct pt_regs*), const char *name)rtl_free_soft_irq( int )rtl_global_pend_irq(int)

These soft IRQ primitives being called from RTLinux environment allows aRTLinux thread or a RTLinux handler to signal an event to Linux.

One in Linux environment, the handler can make use of Linux primitives likewakeup() to wake up a sleeping task or up() to release a Linux semaphore.

4.8) Signaling to Linux with Virtual Hard IRQ

RTLinux provides a way to simulate a Hard IRQ to Linux.

If one uses the pthread_kill(thread,signal) function on the Linux thread, it is re-arrange to simulate a hardware interruption, making the interrupt referred bysignal pending.

Page 81: WP10 -D10.8 Programmer's Guide - MNIS

5) Driver to system interface

In the last chapter we have seen all the system routines and macro we can useto synchronize the different part of the RTLinux and Linux System.

We learned to enable and disable interruptions, to protect memory spaces andto signal events

5.1) registering an irq handler

RTLinux provides two primitives to register and unregister an IRQ handler:

rtl_request_global_irq(irq,isr)rtl_free_global_irq( irq )

RTLinux proposes a way to set IRQ targetted interrupt enabling/disabling:

rtl_hard_disable_irq(unsigned int ix)rtl_hard_enable_irq(unsigned int ix)

5.2) registering a driver

Registering a driver is not mandatory but may be used if one want to takeadvantage of the POSIX IO interface. See the chapter on POSIX IO.

The functions to register and unregister a device are:

int rtl_register_rtldev(unsigned int major, const char * name, struct rtl_file_operations *fops))int rtl_unregister_rtldev(unsigned int major, const char * name)

The rtl_file_operations structure is composed of the following entries:

struct rtl_file_operations { loff_t (*llseek) (struct rtl_file *, loff_t, int); ssize_t (*read) (struct rtl_file *, char *, size_t, loff_t *); ssize_t (*write) (struct rtl_file *, const char *, size_t, loff_t *);

Page 82: WP10 -D10.8 Programmer's Guide - MNIS

int (*ioctl) (struct rtl_file *, unsigned int, unsigned long); int (*mmap) (struct rtl_file *, void *start, size_t length, int prot , int flags, off_t offset,caddr_t *result); int (*open) (struct rtl_file *); int (*release) (struct rtl_file *);};

6) Examples

Let see how the OCERA stream driver uses the Driver's framework.

This diver is well suited for an example because it is quite short and because itmakes use of both Linux and RTLinux synchronization mechanisms.

6.1) Compilation and modules declarations

The file makefile.omk is used to compile the module:

ifeq ($(CONFIG_OC_STREAMS),y)

SYSTEM = RTLINUX_V3VERSION = 0.1.0

rtlinux_INCLUDES += -D$(SYSTEM) -DVERSION=\"$(VERSION)\"

rtlinux_MODULES = ocs

rtlinux_HEADERS = ocs.hocs_SOURCES = ocs_main.c ocs_proc.c

endif #CONFIG_OC_STREAMS

The module is initialzed by the init_module and cleanup_module routines. Theseroutines do the following job:

Page 83: WP10 -D10.8 Programmer's Guide - MNIS

a) Initialization

int init_module(void){

register short i=0;register ocs_t *ost_p;char name[5];struct proc_dir_entry * pdep;

printk( KERN_INFO "Ocera Streams ("VERSION") ");if( ocs_state != OCERA_STREAMS_STATE_VOID ) {

return(-1);}

ocs_state = OCERA_STREAMS_STATE_INIT ;

b) Define /proc entries

Proc entries are defined to show internal variables to Linux user's environment.The user may also set the debug level.

proc_ocera=proc_mkdir("ocera",0);proc_ocs=proc_mkdir("ocs",proc_ocera);proc_ocs_slot=proc_mkdir("streams_slot",proc_ocs);create_proc_read_entry("state", 0, proc_ocs, ocs_read_proc_state, NULL);create_proc_read_entry("freemsg", 0, proc_ocs, ocs_read_proc_msgbuf, NULL);pdep = create_proc_entry("debug", S_IRUGO | S_IWUSR, proc_ocs);if (pdep) {

pdep->write_proc = ocs_deblevel_write;pdep->read_proc = ocs_deblevel_read;

}

c) Use of Linux functions in init and cleanup

In the init and cleanup routines, you have a context, it is the context of theinsmod programm inserting the module into the kernel.

You must do there all allocations where the function call may sleep.

If you allocate memory to be used by RTLinux you must lock the memory in theKernel space.

printk( "(C)2004 Pierre Morel - MNIS\n");/* initialise the streams tables */

ocs_table_lock=SPIN_LOCK_UNLOCKED; for(i=0;i<MAX_OCERA_STREAMS;i++) {

ost_p = &ocs_table[i];memset(ost_p,0,sizeof(ocs_t));

ost_p->s_state = OCERA_STREAMS_STATE_FREE; strncpy(ost_p->s_name,default_name,strlen(default_name)); ost_p->s_queue_up.q_stream=ost_p; ost_p->s_queue_down.q_stream=ost_p; ost_p->s_queue_wait.q_stream=ost_p;

ost_p->s_queue_up.q_lock=SPIN_LOCK_UNLOCKED;

Page 84: WP10 -D10.8 Programmer's Guide - MNIS

ost_p->s_queue_down.q_lock=SPIN_LOCK_UNLOCKED;ost_p->s_queue_wait.q_lock=SPIN_LOCK_UNLOCKED;

sprintf(name,"%02x",i);create_proc_read_entry(name, 0, proc_ocs_slot, ocs_read_proc_slot,

&ocs_table[i]); }

6.2) Registering the Soft IRQ

In the ocs driver, the soft IRQ is registered by the ocs_register function:

This function make use of several routines we presented like:

rtl_spin_lock_irqsave()rtl_spin_unlock_irqrestore()rtl_get_softirq()

In this function, it is supposed that the type argument gives the environment fromwhere it is called because

• if it is called from Linux, it will initialize the synchronization mechanismwith Linux waitqueues using init_waitqueue_head() and

• if it is called by RTLinux thread it will initialize the synchronizationmechanism with RTLinux semaphores using sem_init().

ocs_t * ocs_register(char * name , int type ){

register ocs_t *ost_p;register int i;unsigned long flags;

rtl_spin_lock_irqsave(&ocs_table_lock,flags);if ( ocs_state != OCERA_STREAMS_STATE_RUNNING ) {

rtl_spin_unlock_irqrestore(&ocs_table_lock,flags);return((ocs_t *)0);}

for( i=0; i< MAX_OCERA_STREAMS ; i++) {ost_p = &ocs_table[i];if( ost_p->s_state == OCERA_STREAMS_STATE_FREE ) {

ost_p->s_state=OCERA_STREAMS_STATE_BUSY; strncpy(ost_p->s_name,name,strlen(name));

ost_p->s_type=type;ocs_free--;if ((type & ST_LINUX_TYPE )) {if ((ost_p->s_queue_up.q_soft = rtl_get_soft_irq (ocs_isr, name)) == 0 ){

ost_p->s_state=OCERA_STREAMS_STATE_FREE;ocs_free++;rtl_spin_unlock_irqrestore(&ocs_table_lock,flags);return((ocs_t *) 0);

}

Page 85: WP10 -D10.8 Programmer's Guide - MNIS

a) synchronization

ost_p->s_queue_down.q_soft = ost_p->s_queue_up.q_soft;ost_p->s_queue_wait.q_soft = ost_p->s_queue_up.q_soft;init_waitqueue_head(&ost_p->s_queue_up.q_sem_s);init_waitqueue_head(&ost_p->s_queue_down.q_sem_s);init_waitqueue_head(&ost_p->s_queue_wait.q_sem_s);

} else {ost_p->s_queue_up.q_soft = 0 ;sem_init (&ost_p->s_queue_down.q_sem_r, 1, 0);sem_init (&ost_p->s_queue_up.q_sem_r, 1, 0);sem_init (&ost_p->s_queue_wait.q_sem_r, 1, 0);

}rtl_spin_unlock_irqrestore(&ocs_table_lock,flags);return(ost_p);}

}rtl_spin_unlock_irqrestore(&ocs_table_lock,flags);return((ocs_t *) 0);

}

6.3) Synchronization

The synchronization with Linux or RTLinux is done by the functions ocs_sleepand ocs_wakeup, using semaphore synchronization for RTLinux and tasksynchronization for Linux.

int ocs_sleep(ocera_msgbuf_q *q, int mode) {int ret=0;if ( mode & OCS_RTL) {

ret = sem_wait(&q->q_sem_r);}else if ( q->q_soft ) {

interruptible_sleep_on(&q->q_sem_s);ret=signal_pending(current);

} else {ret=-1;

}return ret ;

}

void ocs_wakeup(ocera_msgbuf_q *q) {if ( q->q_soft ){

rtl_global_pend_irq(q->q_soft);} else {

sem_post(&q->q_sem_r);}

}

Page 86: WP10 -D10.8 Programmer's Guide - MNIS

The IRQ handler doing the final wakeup:

void ocs_isr(int irq, void *dev_id, struct pt_regs *p){ocs_t *s;int i;

for( i=0; i< MAX_OCERA_STREAMS ; i++ ) {s = &ocs_table[i];if ( s->s_queue_up.q_soft == irq ) {

if ( s->s_state == OCERA_STREAMS_STATE_BUSY){wake_up_interruptible(&s->s_queue_up.q_sem_s);wake_up_interruptible(&s->s_queue_down.q_sem_s);wake_up_interruptible(&s->s_queue_wait.q_sem_s);current->need_resched = 1;return;}

}}

}

6.4) Linux communication with /proc

The communication between the Linux kernel and RTLinux is direct: they use thesame address space.

It is different with Linux User's programs, like the one being used to retrieveinformations through the procfs entries.

A function allow us do do this easily:

static int proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof, int len){ if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len>count) len = count; if (len<0) len = 0; return len;}

Now the function to report the state of the driver is just:

int ocs_read_proc_state(char *page, char **start, off_t off, int count, int *eof, void *data){int len;

len=sprintf(page,"%02lx %0d\n",ocs_state,ocs_free);return proc_calc_metrics(page, start, off, count, eof, len);}

Page 87: WP10 -D10.8 Programmer's Guide - MNIS

PART VPART VOCERA Components

Page 88: WP10 -D10.8 Programmer's Guide - MNIS

VI) Quality Of Services

ByLuca Marzario - SSSA

in attachment there are two file that are a skeleton for program thatwant to use reservation and feedback schedulingBefore run that program, naturally, user have to insert the relativemodule (cbs_sched.o and qmgr_sched.o) into the kernel with insmodcommand. No other steps are needed (you are right: the patch is alreadyintegrated).

/* * Copyright (C) 2003 Luca Marzario * This is Free Software; see GPL.txt for details */

#include <stdio.h>#include <stdlib.h>#include <unistd.h>

#include <sched.h>#define __QMGR__#include "qmgr.h"#define CBS_PERIOD 10000 /* period of reservation */#define QMGR_MAX_BUDGET 5000 /* max budget that can be asssigned to CBS server */#define QMGR_PERIOD 80000 /* period of feedback function */#define QMGR_MIN_EXEC 5000 /* minimum exstimated execution time */#define QMGR_MAX_EXEC 60000 /* maximum exstimated execution time */#define QMGR_LOW_ERR 0 /* desired lower bound of scheduling error */#define QMGR_HIGH_ERR 5000 /* desired upper bound of scheduling error */#define QMGR_MIN_ERR 0 /* absolute minimum scheduling error */#define QMGR_MAX_ERR 10000 /* absolute maximum scheduling error */

#define qmgr_end_cycle()

int main(int argc, char *argv[]){ struct sched_param sp; struct qmgr_param cs; int res, cond = 0;

sp.sched_size = sizeof(struct qmgr_param);

Page 89: WP10 -D10.8 Programmer's Guide - MNIS

sp.sched_p = &cs; cs.cbs_period = CBS_PERIOD; cs.qmgr_max_b = QMGR_MAX_BUDGET; cs.qmgr_period = QMGR_PERIOD; cs.qmgr_signature = QMGR_SIGNATURE;

/* parameters for feedback function */ cs.h = QMGR_MIN_EXEC; cs.H = QMGR_MAX_EXEC; cs.ei = QMGR_LOW_ERR; cs.Ei = QMGR_HIGH_ERR; cs.e = QMGR_MIN_ERR; cs.E = QMGR_MAX_ERR;

/* if you donn't need particular scheduling error target, you can use default values: substitute assignment of parameters fo feedback function with the following call:

qmgr_init_default(&cs); */

res = sched_setscheduler(getpid(), SCHED_CBS, &sp); if (res < 0) { perror("Error in setscheduler!"); exit(-1); } do {

/* my code */

qmgr_end_cycle();

} while ( cond ); /* exit condition */ return 0;}

Programs 2

#include <stdio.h>#include <stdlib.h>#include <unistd.h>

#include <sched.h>#include "cbs.h"

extern char **environ;

#define MAX_BUDEGET_US 10000 /* max budget per period in us */#define RESERV_PERIOD_US 100000 /* period of reservation in us*/

Page 90: WP10 -D10.8 Programmer's Guide - MNIS

int main(int argc, char *argv[]){ struct sched_param sp; /* used to pass parameters to qres module throug setsched */ struct cbs_param cs; /* " */ int res; sp.sched_size = sizeof(struct cbs_param); sp.sched_p = &cs; cs.signature = CBS_SIGNATURE; cs.type = CBS_TYPE_DEFAULT; cs.max_budget = MAX_BUDEGET_US; cs.period = RESERV_PERIOD_US;

res = sched_setscheduler(getpid(), SCHED_CBS, &sp); if (res < 0) { perror("Error in setscheduler!"); exit(-1); }

/* my code */

return 0;}

Page 91: WP10 -D10.8 Programmer's Guide - MNIS

VII) Network API

ByPierre Morel – MNIS

1) Driver's presentation

1.1) Overview

The access to the network goes through Linux kernel thread and use the LinuxTCP/IP stack. The implementation is called Onetd for Ocera NETwork Daemon.

The RTLinux thread calls Onetd Network API to interact with the driver, thisinterface is very near from the standard BSD socket API.

Beside the API, a user can interact with the driver from the Linux environment by

• getting and setting variables in the /proc special filesytem, • sending signals to the Onetd daemons • or looking at the processes running by using the ps command.

See the User's Guide for more informations on the way to use configure Onetd.

1.2) RTLinux/Linux communication

The communication between the Real-time world in RTLinux and the TimeSharing world under Linux is done by a module called ocs which means OCeraStreams.

Page 92: WP10 -D10.8 Programmer's Guide - MNIS

It has little to do with the System V streams and it does not implement all theSvr4 streams features.

I prefer to define it as a stackable zero copy message passing system workingeither with RTLinux or Linux threads synchronization.

In this definition the words thread synchronization means that you cannot use itinside any interrupt part of a driver, neither Linux nor RTLinux, because it useswait/post RTLinux semaphores and sleep/wakeup Linux synchronization. So youneed a task or thread context.

The change between real-time world and time-sharing world is done by issuingfrom RTLinux a soft interrupt to Linux.

1.3) Protocols

At the moment we write these lines, only a UDP access to the IF_INET stack isallowed. TCP and raw socket access will be soon available.

1.4) Memory allocation

You are, as user, responsible of the memory allocation for all the data you wantto transmit or receive over the network. You will need to provide Onetd with abuffer to receive the data.

1.5) Configuration issues

You can configure the following values in the Onetd and Ocs header files:

a) In ocs.h

name Defaultvalue

Commentary

MAX_OCERA_STREAMS 64 You need two streams for each openconnection

ODEBUG 1 A value of 1 means ocs and onetd arecompiled with DEBUG

Page 93: WP10 -D10.8 Programmer's Guide - MNIS

name Defaultvalue

Commentary

ocs_deblevel 0 Value can be from 0 to 5.

5 means all debug info.4 means streams debug 3 means function call2 means low debug1 means error only0 means no debug shown

MAX_MSGBUF 128 The number of message buffers in thesystem. Each one correspond to apacket. At most.

b) In onetd.h

name Defaultvalue

Commentary

MAX_OCERA_SOCKET 32 You need one socket for eachconnection.

2) Network API

Writing a program with the Onetd Network API is straight forward from anystandard BSD like socket API.

You find the following calls:

extern int ocn_socket(int, int , int);extern int ocn_bind(int , struct sockaddr_in *, int);extern int ocn_getsockname(int , struct sockaddr_in *, int);

Page 94: WP10 -D10.8 Programmer's Guide - MNIS

extern int ocn_sendto(int, void *, size_t, int, struct sockaddr_in *, int);extern int ocn_recvfrom(int, void *, size_t, int, struct sockaddr_in *, int *);extern int ocn_close(int);extern int ocn_delete(int);extern int ocn_setsockopt(int,int,int,char *,int);extern int ocn_getsockopt(int,int,int,char *,int *);extern int ocn_ioctl(int, unsigned int , void * );

Page 95: WP10 -D10.8 Programmer's Guide - MNIS

2.1) ocn_socket

NAMEocn_socket – create an endpoint for communication

SYNOPSIS#include <onetd.h>

extern int ocn_socket(int domain, int type , int protocol);

DESCRIPTION

Socket creates an endpoint for communication and returns a descriptor.

The domain parameter specifies a communication domain; this selects theprotocol family which will be used for communication. These families aredefined in <sys/socket.h>.

The only protocol accepted for now is PF_INET

The type specify the communication semantics.

The only type accepted for now is SOCK_DGRAM

The protocol field is used to specify a protocol associated with the type.

For now this field is not used.

RETURN VALUE

-1 is returned if an error occurs; otherwise the return value is a descriptorreferencing the socket.

Page 96: WP10 -D10.8 Programmer's Guide - MNIS

2.2) ocn_sendto

NAMEocn_sendto - send a message from a socket

SYNOPSISextern int ocn_sendto(int s, void *buf, size_t len, int flags, struct sockaddr_in *to,int tolen);

DESCRIPTION

The call sendto is used to transmit the message in the buffer buf with length lento another socket specified by the socket address to.

The local point reference s must have been initialized by a ocn_socket call.

The flags can be:

MSG_WAITALL or MSG_DONTWAIT

RETURN VALUE

In case of success, a positive value: the transmitted length.

In case of error, a negative value indicating the cause of the error:

EAGAIN: means no resources, try again.

EBADF: means the driver was in an invalid state.

Page 97: WP10 -D10.8 Programmer's Guide - MNIS

2.3) ocn_getsockname

NAME

ocn_getsockname – get socket name

SYNOPSIS

#include <onetd.h>

extern int ocn_getsockname(int , struct sockaddr_in *, int);

DESCRIPTION

ocn_getsockname returns the current address and port of the socket, it is usefulwhen first binding to an unknown address by specifying a wild card to theocn_bind call.

RETURN VALUE

0 means success, -1 means an error occurred.

Page 98: WP10 -D10.8 Programmer's Guide - MNIS

2.4) ocn_recvfrom

NAME ocn_recvfrom – receive a message from a socket

SYNOPSIS#include <onetd.h>

extern int ocn_recvfrom(int s, void * buffer, size_t len, int flags, structsockaddr_in * from, int *fromlen);

DESCRIPTION

fills the buffer buf with at most len data received on the socket descriptordescribed by s . The address of the remote endpoint is given in from if theprotocol provides it.

The flags can be:

MSG_WAITALL or MSG_DONTWAIT

RETURN VALUE

In case of success, a positive value: the received length.

In case of error, a negative value indicating the cause of the error:

EAGAIN: means no resources, try again.

EBADF: means the driver was in an invalid state.

Page 99: WP10 -D10.8 Programmer's Guide - MNIS

2.5) ocn_close

NAME

ocn_close – free a socket

SYNOPSIS#include <onetd.h>

extern int ocn_close(int);

DESCRIPTION

Free the socket structures.

RETURN VALUE

In case of success returns 0.

In case of error, a negative value indicating the cause of the error:

EBADF: means the driver was in an invalid state.

Page 100: WP10 -D10.8 Programmer's Guide - MNIS

2.6) ocn_setsockopt

NAME

ocn_setsockopt – set the socket options

SYNOPSIS#include <onetd.h>

extern int ocn_setsockopt(int,int,int,char *,int);

DESCRIPTION

The options are directly passed to the Linux socket.

See socket(7) for the description of the different options.

RETURN VALUE

In case of success returns 0.

In case of error, a negative value indicating the cause of the error:

EBADF: means the driver was in an invalid state.

Page 101: WP10 -D10.8 Programmer's Guide - MNIS

2.7) ocn_getsockopt

NAME

ocn_getsockopt – get the socket options

SYNOPSIS#include <onetd.h>

extern int ocn_getsockopt(int,int,int,char *,int *);

DESCRIPTION

The options are directly passed to the Linux socket.

See socket(7) for the description of the different options.

RETURN VALUE

In case of success returns 0.

In case of error, a negative value indicating the cause of the error:

EBADF: means the driver was in an invalid state.

Page 102: WP10 -D10.8 Programmer's Guide - MNIS

2.8) ocn_ioctl

NAME

ocn_ioctl – send socket specific IO control. See set/getsockopt

SYNOPSIS#include <onetd.h>

extern int ocn_ioctl(int, unsigned int , void*);

DESCRIPTION

Send/get options through ioctl.

See socket(7) for more informations.

RETURN VALUE

In case of success returns 0.

In case of error, a negative value indicating the cause of the error:

EBADF: means the driver was in an invalid state.

3) Programming examples

The two programs hereunder are called ping and pong.

Page 103: WP10 -D10.8 Programmer's Guide - MNIS

As their name suggest , ping send data over the network and pong replies tohim, ping then replies to pong and so on.The applications are real time applications and are compiled as modules.

3.1) Ping

/* * Ping: reply to UDP packet and increment a counter */#include <linux/config.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/socket.h>#include <linux/in.h>

#include <pthread.h>#include <time.h>#include <unistd.h>

#include <asm/system.h>#include <asm/io.h>

#include <rtl.h>#include <rtl_fifo.h>

#define RTL_SPIN_LOCK SPIN_LOCK_UNLOCKED#include <rtl_sync.h>#include "../onetd.h"

MODULE_AUTHOR("Pierre Morel <[email protected]>");MODULE_DESCRIPTION("Ocera Network ping module example");MODULE_LICENSE("GPL");

/* * Initialize the module, get queues and wait for data */

int period = OCS_PERIOD*100 ;

pthread_t ping_thread;

#define RECEIVE_BUFFER_SIZE 1024char my_receive_buffer [RECEIVE_BUFFER_SIZE];

#define MSG_LEN 128char my_message [MSG_LEN];

Page 104: WP10 -D10.8 Programmer's Guide - MNIS

/*#define REM_ADDR INADDR_LOOPBACK*//* 192.168.254.5#define REM_ADDR 0xc0a8fe05#define REM_ADDR INADDR_LOOPBACK*/#define LOC_ADDR INADDR_ANY#define MY_PORT 0

#define REM_PORT (unsigned short) 10061#define REM_ADDR INADDR_LOOPBACK

int sock=-1;static struct sockaddr_in my_socket;static struct sockaddr_in rem_socket;static struct sockaddr_in rem_socket2;char *my_name = "ping";

/* * PING THREAD */

void *ping_rt_thread(void *t){int err;int count=0;int count2=0;int len;

ODEBUGP(ODEB_CALL,( KERN_INFO "PING: ping_rt_thread\n"));sprintf(my_message,"RT MESSAGE %d",count);ODEBUGP(ODEB_CALL,( KERN_INFO "PING: pthread_make_periodic_np\n"));pthread_make_periodic_np( pthread_self(), gethrtime(), period );rem_socket.sin_family = AF_INET;rem_socket.sin_addr.s_addr = htonl(REM_ADDR);rem_socket.sin_port = htons(REM_PORT);

my_socket.sin_family = AF_INET;my_socket.sin_addr.s_addr = LOC_ADDR;my_socket.sin_port = htons(MY_PORT);

/*ocs_deblevel=ODEB_CALL;*/

ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Binding\n"));

sock = ocn_socket(AF_INET,SOCK_DGRAM,0);ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Bound to %d\n",sock));ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Closing %d\n",sock));ocn_close(sock);ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Binding 2\n"));sock = ocn_socket(AF_INET,SOCK_DGRAM,0);ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Bound to %d\n",sock));if ( sock >= 0 ) {

err = ocn_bind(sock,&my_socket,sizeof(struct sockaddr_in));

Page 105: WP10 -D10.8 Programmer's Guide - MNIS

if ( err ){ODEBUGP(ODEB_CALL,( KERN_INFO "PING: bind error: %d\n",err));return(0);

}else {

ODEBUGP(ODEB_CALL,( KERN_INFO "PING: bind ok on: %d\n",sock));

}} else {

ODEBUGP(ODEB_CALL,( KERN_INFO "PING: socket error: %d\n",sock));return(0);

}ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Bound to: %08x port %

d\n",my_socket.sin_addr.s_addr, my_socket.sin_port));len = sizeof(struct sockaddr_in);if ( ocn_getname(sock, (struct sockaddr *)&my_socket , &len) ) {

ODEBUGP(ODEB_CALL,( KERN_INFO "PING: ocn_getname error\n"));ocn_delete(sock);return(0);

}ODEBUGP(ODEB_CALL,( KERN_INFO "PING: Bound to: %08x port %

d\n",my_socket.sin_addr.s_addr, my_socket.sin_port));

err=0;count2=0;while(err >= 0 && count2 < 100000 ){

sprintf(my_message,"I shot the sheriff %04d",count2);my_message[24]=0;rtl_printf("PING: %s\n",my_message);err=ocn_sendto

(sock,&my_message,MSG_LEN,MSG_WAITALL,&rem_socket,sizeof(struct sockaddr_in));if ( err >= 0 ) {

count2++;len=sizeof(struct sockaddr_in);err = ocn_recvfrom

(sock,my_receive_buffer,RECEIVE_BUFFER_SIZE,MSG_WAITALL,&rem_socket2,&len) ;my_receive_buffer[36]=0;rtl_printf("PING: %s\n",my_receive_buffer);

}}ODEBUGP(ODEB_CALL,( KERN_INFO "PING: CALL CLOSE\n"));ocn_close(sock);ODEBUGP(ODEB_CALL,( KERN_INFO "PING: END\n"));return(0);

}

int init_module( void ) {int thread_status;pthread_attr_t attr;struct sched_param sched_param;

pthread_attr_init(&attr);sched_param.sched_priority = 4;pthread_attr_setschedparam(&attr,&sched_param);thread_status=pthread_create(&ping_thread, &attr,ping_rt_thread,(void *)1);

Page 106: WP10 -D10.8 Programmer's Guide - MNIS

if ( thread_status < 0 ){printk( KERN_INFO "ocera streams ping: pthread_create error.\n");return(-1);}

printk( KERN_INFO "ocera ping (version "VERSION ") sucessfully loaded.\n" KERN_INFO "ocera ping: Copyright (C) 2003 Pierre Morel.\n" );

return(0);}

void cleanup_module( void ){

printk( KERN_INFO "ocera streams ping cleanup sock %d.\n",sock );ocn_delete(sock);pthread_delete_np (ping_thread);printk( KERN_INFO "ocera streams ping unloaded.\n" );return;

}

3.2) pong

/* * Pong: reply to UDP packet and increment a counter */#include <linux/config.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/socket.h>#include <linux/in.h>

#include <pthread.h>#include <time.h>#include <unistd.h>

#include <asm/system.h>#include <asm/io.h>

#include <rtl.h>#include <rtl_fifo.h>

#define RTL_SPIN_LOCK SPIN_LOCK_UNLOCKED#include <rtl_sync.h>#include "../onetd.h"

MODULE_AUTHOR("Pierre Morel <[email protected]>");MODULE_DESCRIPTION("Ocera Network pong module example");MODULE_LICENSE("GPL");

Page 107: WP10 -D10.8 Programmer's Guide - MNIS

/* * Initialize the module, get queues and wait for data */

int period = OCS_PERIOD*100 ;

pthread_t pong_thread;

ocera_msgbuf_t *tmp;

#define RECEIVE_BUFFER_SIZE 1024char my_receive_buffer [RECEIVE_BUFFER_SIZE];

#define MSG_LEN 128char my_message [MSG_LEN];

/* 192.168.254.5#define REM_ADDR 0xc0a8fe05#define REM_ADDR htonl(INADDR_LOOPBACK)*/#define LOC_ADDR INADDR_ANY#define MY_PORT (unsigned short) 10061

static int sock=-1;static struct sockaddr_in my_socket;static struct sockaddr_in rem_socket;char *my_name = "pong";

/* * PONG THREAD */

void *pong_rt_thread(void *t){int flags;int err;int count2 = 0;int len;

ODEBUGP(ODEB_CALL,( KERN_INFO "PONG: pthread_make_periodic_np\n"));pthread_make_periodic_np( pthread_self(), gethrtime(), period );my_socket.sin_family = AF_INET;my_socket.sin_addr.s_addr = LOC_ADDR;my_socket.sin_port = htons(MY_PORT);

ocs_deblevel=0;

ODEBUGP(ODEB_CALL,( KERN_INFO "PONG: Binding\n"));

sock=ocn_socket(AF_INET,SOCK_DGRAM,0);if ( (err=ocn_bind(sock,&my_socket,sizeof(struct sockaddr_in)))){

ODEBUGP(ODEB_CALL,( KERN_INFO "PONG: Binding error %d\n",err));ocn_delete(sock);return(0);

Page 108: WP10 -D10.8 Programmer's Guide - MNIS

}flags = MSG_WAITALL;memset(my_receive_buffer,'A',20);my_receive_buffer[20]=0;while ( err >= 0) {

len=sizeof(struct sockaddr_in);err = ocn_recvfrom

(sock,my_receive_buffer,RECEIVE_BUFFER_SIZE,flags,&rem_socket,&len) ;if ( err >= 0 ) {

my_receive_buffer[25]=0;rtl_printf("PONG: %s\n",my_receive_buffer);memset(my_receive_buffer,'A',20);sprintf(my_message,"But I didn't shoot the deputy %04d",count2);my_message[36]=0;err=ocn_sendto

(sock,&my_message,MSG_LEN,MSG_WAITALL,&rem_socket,sizeof(struct sockaddr_in));count2++;

}}ODEBUGP(ODEB_CALL,( KERN_INFO "PONG: CALL CLOSE\n"));ocn_close(sock);

ODEBUGP(ODEB_CALL,( KERN_INFO "PONG: END\n"));return(0);

}

int init_module( void ){

int thread_status;pthread_attr_t attr;struct sched_param sched_param;

pthread_attr_init(&attr);sched_param.sched_priority = 4;pthread_attr_setschedparam(&attr,&sched_param);thread_status=pthread_create(&pong_thread, &attr,pong_rt_thread,(void *)1);

if ( thread_status < 0 ){printk( KERN_INFO "ocera streams pong: pthread_create error.\n");return(-1);}

printk( KERN_INFO "ocera pong (version "VERSION ") sucessfully loaded.\n" KERN_INFO "ocera pong: Copyright (C) 2003 Pierre Morel.\n" );return(0);}

void cleanup_module( void ){

if(sock >= 0 ) {ocn_delete(sock);

}pthread_delete_np (pong_thread);printk( KERN_INFO "ocera streams pong unloaded.\n" );return;

}

Page 109: WP10 -D10.8 Programmer's Guide - MNIS

3.3) Makefile

# Standalone Makefile for ocera_net## Copyright (C) 2004 Pierre Morel

# in accordance with your system#.SUFFIXES: .o .ps .c .h

SYSTEM = RTLINUX_V3RTLINUX_DIR = /usr/share/ocera_1.0.0/kernel/rtlinuxINCLUDEDIR = $(RTLINUX_DIR)/include/

DISTFILES = pong.c ping.c

OBJS = pong.o ping.o

VERSION = 0.0.1

include $(RTLINUX_DIR)/rtl.mk

CFLAGS += -D$(SYSTEM) -DVERSION=\"$(VERSION)\"

.c.o: Makefile $(DISTFILES)$(CC) $(CFLAGS) -c $<

.c.ps: $(DISTFILES)a2ps -o $*.ps $*.c

.h.ps: a2ps -o $*.ps $<

all: $(OBJS)

clean:rm *.o

load:modprobe onetdinsmod ./pong.oinsmod ./ping.o

unload:rmmod pongrmmod pingrmmod onetdrmmod ocs

Page 110: WP10 -D10.8 Programmer's Guide - MNIS

VIII) OCERA Real-TimeEthernet

ByJan Krakora CTUPavel Pisa CTUFrantisek Vacek CTUZdenek Sebek CTUPetr Smolik CTUZdenek Hanzalek CTU

The Ocera Real-Time Ethernet (ORTE) is open source implementation of RTPScommunication protocol. RTPS is new application layer protocol targeted to real-time communication area, which is build on the top of standard UDP stack. Sincethere are many TCP/IP stack implementations under many operating systemsand RTPS protocol does not have any other special HW/SW requirements, itshould be easily ported to many HW/SW target platforms. Because it uses onlyUDP protocol, it retains control of timing and reliability.

1.1) ORTE API

a) Data types

Table of Contentsenum SubscriptionMode -- mode of subscription enum SubscriptionType -- type of subcsription enum ORTERecvStatus -- status of a subscription enum ORTESendStatus -- status of a publication struct ORTEIFProp -- interface flags struct ORTEMulticastProp -- properties for ORTE multicast (not supported yet) struct ORTECDRStream -- used for serialization struct ORTETypeRegister -- registered data type struct ORTEDomainBaseProp -- base properties of a domain struct ORTEDomainWireProp -- wire properties of a message struct ORTEPublProp -- properties of a publication

Page 111: WP10 -D10.8 Programmer's Guide - MNIS

struct ORTESubsProp -- properties of a subscription struct ORTEAppInfo -- struct ORTEPubInfo -- information about publication struct ORTESubInfo -- information about subscription struct ORTEPublStatus -- status of a publication struct ORTESubsStatus -- status of a subscription struct ORTERecvInfo -- description of received data struct ORTESendInfo -- description of sending data struct ORTEDomainAppEvents -- Domain event handlers of an application struct ORTETasksProp -- ORTE task properties, not supported struct ORTEDomainProp -- domain properties

1.2) enum SubscriptionMode

a) Name

enum SubscriptionMode -- mode of subscription

b) Synopsis enum SubscriptionMode { PULLED, IMMEDIATE };

c) Constants

PULLED

polled

IMMEDIATE

using callback function

d) Description

Specifies whether user application will poll for data or whether a callback functionwill be called by ORTE middleware when new data will be available.

1.3) enum SubscriptionType

a) Name

enum SubscriptionType -- type of subcsription

Page 112: WP10 -D10.8 Programmer's Guide - MNIS

b) Synopsis enum SubscriptionType { BEST_EFFORTS, STRICT_RELIABLE };

c) Constants

BEST_EFFORTS

best effort subscription

STRICT_RELIABLE

strict reliable subscription.

d) Description

Specifies which mode will be used for this subscription.

1.4) enum ORTERecvStatus

a) Name

enum ORTERecvStatus -- status of a subscription

b) Synopsis enum ORTERecvStatus { NEW_DATA, DEADLINE };

c) Constants

NEW_DATA

new data has arrived

DEADLINE

deadline has occurred

d) Description

Specifies which event has occured in the subscription object.

Page 113: WP10 -D10.8 Programmer's Guide - MNIS

1.5) enum ORTESendStatus

a) Name

enum ORTESendStatus -- status of a publication

b) Synopsis enum ORTESendStatus { NEED_DATA, CQL };

c) Constants

NEED_DATA

need new data (set when callback function specified for publciation isbeeing called)

CQL

transmit queue has been filled up to critical level.

d) Description

Specifies which event has occured in the publication object. Critical level oftransmit queue is specified as one of publication properties(ORTEPublProp.criticalQueueLevel).

2) struct ORTEIFProp

2.1) Name

struct ORTEIFProp -- interface flags

Page 114: WP10 -D10.8 Programmer's Guide - MNIS

2.2) Synopsis

struct ORTEIFProp { int32_t ifFlags; IPAddress ipAddress; };

2.3) Members

ifFlags

flags

ipAddress

IP address

2.4) Description

Flags for network interface.

3) struct ORTEMulticastProp

3.1) Name

struct ORTEMulticastProp -- properties for ORTE multicast (not supported yet)

Page 115: WP10 -D10.8 Programmer's Guide - MNIS

3.2) Synopsis

struct ORTEMulticastProp { Boolean enabled; unsigned char ttl; Boolean loopBackEnabled; IPAddress ipAddress; };

3.3) Members

enabled

ORTE_TRUE if multicast enabled otherwise ORTE_FALSE

ttl

time-to-live (TTL) for sent datagrams

loopBackEnabled

ORTE_TRUE if data should be received by sender itself otherwiseORTE_FALSE

ipAddress

desired multicast IP address

3.4) Description

Properties for ORTE multicast subsystem which is not fully supported yet.Multicast IP address is assigned by the ORTE middleware itself.

Page 116: WP10 -D10.8 Programmer's Guide - MNIS

4) struct ORTECDRStream

4.1) Name

struct ORTECDRStream -- used for serialization

4.2) Synopsis

struct ORTECDRStream { char * buffer; char * bufferPtr; Boolean needByteSwap; int length; };

4.3) Members

buffer

buffer for data

bufferPtr

current position within buffer

needByteSwap

ORTE_TRUE if it is necessary to swap byte ordering otherwiseORTE_FALSE

length

buffer length

Page 117: WP10 -D10.8 Programmer's Guide - MNIS

4.4) Description

Struct ORTECDRStream is used by serialization and deserialization functions.

5) struct ORTETypeRegister

5.1) Name

struct ORTETypeRegister -- registered data type

5.2) Synopsis

struct ORTETypeRegister { const char * typeName; ORTETypeSerialize serialize; ORTETypeDeserialize deserialize; unsigned int getMaxSize; };

5.3) Members

typeName

name of data type

serialize

pointer to serialization function

deserialize

Page 118: WP10 -D10.8 Programmer's Guide - MNIS

pointer to deserialization function

getMaxSize

max data type length in bytes

5.4) Description

Contains description of registered data type. See ORTETypeRegisterAddfunction for details.

6) struct ORTEDomainBaseProp

6.1) Name

struct ORTEDomainBaseProp -- base properties of a domain

6.2) Synopsis

struct ORTEDomainBaseProp { NtpTime expirationTime; NtpTime refreshPeriod; NtpTime purgeTime; NtpTime repeatAnnounceTime; NtpTime repeatActiveQueryTime; NtpTime delayResponceTimeACKMin; NtpTime delayResponceTimeACKMax; unsigned int HBMaxRetries; unsigned int ACKMaxRetries; NtpTime maxBlockTime; };

Page 119: WP10 -D10.8 Programmer's Guide - MNIS

6.3) Members

expirationTime

specifies how long is this application taken as alive in otherapplications/managers (default 180s)

refreshPeriod

how often an application refresh itself to its manager or manager to othermanagers (default 60s)

purgeTime

how often the local database should be cleaned from invalid (expired)objects (default 60s)

repeatAnnounceTime

This is the period with which the CSTWriter will announce its existenceand/or the availability of new CSChanges to the CSTReader. This perioddetermines how quickly the protocol recovers when an announcement ofdata is lost.

repeatActiveQueryTime

???

delayResponceTimeACKMin

minimum time the CSTWriter waits before responding to an incomingmessage.

delayResponceTimeACKMax

maximum time the CSTWriter waits before responding to an incomingmessage.

HBMaxRetries

how many times a HB message is retransmitted if no response has beenreceived until timeout

ACKMaxRetries

Page 120: WP10 -D10.8 Programmer's Guide - MNIS

how many times an ACK message is retransmitted if no response has beenreceived until timeout

maxBlockTime

timeout for send functions if sending queue is full (default 30s)

6.4) struct ORTEDomainWireProp

a) Name

struct ORTEDomainWireProp -- wire properties of a message

b) Synopsis struct ORTEDomainWireProp { unsigned int metaBytesPerPacket; unsigned int metaBytesPerFastPacket; unsigned int metabitsPerACKBitmap; unsigned int userMaxSerDeserSize; };

c) Members

metaBytesPerPacket

maximum number of bytes in single frame (default 1500B)

metaBytesPerFastPacket

maximum number of bytes in single frame if transmitting queue hasreached criticalQueueLevel level (see ORTEPublProp struct)

metabitsPerACKBitmap

not supported yet

userMaxSerDeserSize

maximum number of user data in frame (default 1500B)

d) struct ORTEPublProp

Name

struct ORTEPublProp -- properties of a publication

Page 121: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis struct ORTEPublProp { PathName topic; TypeName typeName; TypeChecksum typeChecksum; Boolean expectsAck; NtpTime persistence; u_int32_t reliabilityOffered; u_int32_t sendQueueSize; int32_t strength; u_int32_t criticalQueueLevel; NtpTime HBNornalRate; NtpTime HBCQLRate; unsigned int HBMaxRetries; NtpTime maxBlockTime; };

Members

topic

the name of the information in the Network that is published or subscribedto

typeName

the name of the type of this data

typeChecksum

a checksum that identifies the CDR-representation of the data

expectsAck

indicates wherther publication expects to receive ACKs to its messages

persistence

indicates how long the issue is valid

reliabilityOffered

reliability policy as offered by the publication

sendQueueSize

size of transmitting queue

strength

Page 122: WP10 -D10.8 Programmer's Guide - MNIS

precedence of the issue sent by the publication

criticalQueueLevel

treshold for transmitting queue content length indicating the queue canbecame full immediately

HBNornalRate

how often send HBs to subscription objects

HBCQLRate

how often send HBs to subscription objects if transmittiong queue hasreached criticalQueueLevel

HBMaxRetries

how many times retransmit HBs if no replay from target object has not beenreceived

maxBlockTime

unsupported

6.5) struct ORTESubsProp

a) Name

struct ORTESubsProp -- properties of a subscription

b) Synopsis struct ORTESubsProp { PathName topic; TypeName typeName; TypeChecksum typeChecksum; NtpTime minimumSeparation; u_int32_t recvQueueSize; u_int32_t reliabilityRequested; //additional parametersNtpTime deadline; u_int32_t mode; };

c) Members

topic

Page 123: WP10 -D10.8 Programmer's Guide - MNIS

the name of the information in the Network that is published or subscribedto

typeName

the name of the type of this data

typeChecksum

a checksum that identifies the CDR-representation of the data

minimumSeparation

minimum time between two consecutive issues received by the subscription

recvQueueSize

size of receiving queue

reliabilityRequested

reliability policy requested by the subscription

deadline

deadline for subscription, a callback function (seeORTESubscriptionCreate) will be called if no data were received withinthis period of time

mode

mode of subscription (strict reliable/best effort), see SubscriptionTypeenum for values

d) struct ORTEAppInfo

Name

struct ORTEAppInfo --

Synopsis struct ORTEAppInfo { HostId hostId; AppId appId; IPAddress * unicastIPAddressList; unsigned char unicastIPAddressCount; IPAddress * metatrafficMulticastIPAddressList; unsigned char metatrafficMulticastIPAddressCount;

Page 124: WP10 -D10.8 Programmer's Guide - MNIS

Port metatrafficUnicastPort; Port userdataUnicastPort; VendorId vendorId; ProtocolVersion protocolVersion; };

Members

hostId

hostId of application

appId

appId of application

unicastIPAddressList

unicast IP addresses of the host on which the application runs (there canbe multiple addresses on a multi-NIC host)

unicastIPAddressCount

number of IPaddresses in unicastIPAddressList

metatrafficMulticastIPAddressList

for the purposes of meta-traffic, an application can also accept Messageson this set of multicast addresses

metatrafficMulticastIPAddressCount

number of IPaddresses in metatrafficMulticastIPAddressList

metatrafficUnicastPort

UDP port used for metatraffic communication

userdataUnicastPort

UDP port used for metatraffic communication

vendorId

identifies the vendor of the middleware implementing the RTPS protocoland allows this vendor to add specific extensions to the protocol

protocolVersion

Page 125: WP10 -D10.8 Programmer's Guide - MNIS

describes the protocol version

7) struct ORTEPubInfo

7.1) Name

struct ORTEPubInfo -- information about publication

7.2) Synopsis

struct ORTEPubInfo { const char * topic; const char * type; ObjectId objectId; };

7.3) Members

topic

the name of the information in the Network that is published or subscribedto

type

the name of the type of this data

objectId

object providing this publication

Page 126: WP10 -D10.8 Programmer's Guide - MNIS

7.4) struct ORTESubInfo

a) Name

struct ORTESubInfo -- information about subscription

b) Synopsis struct ORTESubInfo { const char * topic; const char * type; ObjectId objectId; };

c) Members

topic

the name of the information in the Network that is published or subscribedto

type

the name of the type of this data

objectId

object with this subscription

7.5) struct ORTEPublStatus

a) Name

struct ORTEPublStatus -- status of a publication

b) Synopsis struct ORTEPublStatus { unsigned int strict; unsigned int bestEffort; unsigned int issues; };

c) Members

strict

Page 127: WP10 -D10.8 Programmer's Guide - MNIS

count of unreliable subscription (strict) connected on responsiblesubscription

bestEffort

count of reliable subscription (best effort) connected on responsiblesubscription

issues

number of messages in transmitting queue

d) struct ORTESubsStatus

Name

struct ORTESubsStatus -- status of a subscription

Synopsis struct ORTESubsStatus { unsigned int strict; unsigned int bestEffort; unsigned int issues; };

Members

strict

count of unreliable publications (strict) connected to responsiblesubscription

bestEffort

count of reliable publications (best effort) connected to responsiblesubscription

issues

number of messages in receiving queue

struct ORTERecvInfo

Name

struct ORTERecvInfo -- description of received data

Page 128: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis

struct ORTERecvInfo { ORTERecvStatus status; const char * topic; const char * type; GUID_RTPS senderGUID; NtpTime localTimeReceived; NtpTime remoteTimePublished; SequenceNumber sn; };

Members

status

status of this event

topic

the name of the information

type

the name of the type of this data

senderGUID

GUID of object who sent this information

localTimeReceived

local timestamp when data were received

remoteTimePublished

remote timestam when data were published

sn

sequencial number of data

struct ORTESendInfo

Name

struct ORTESendInfo -- description of sending data

Synopsis

struct ORTESendInfo {

Page 129: WP10 -D10.8 Programmer's Guide - MNIS

ORTESendStatus status; const char * topic; const char * type; GUID_RTPS senderGUID; SequenceNumber sn; };

Members

status

status of this event

topic

the name of the information

type

the name of the type of this information

senderGUID

GUID of object who sent this information

sn

sequencial number of information

struct ORTEDomainAppEvents

Name

struct ORTEDomainAppEvents -- Domain event handlers of an application

Synopsis

struct ORTEDomainAppEvents { ORTEOnMgrNew onMgrNew; void * onMgrNewParam; ORTEOnMgrDelete onMgrDelete; void * onMgrDeleteParam; ORTEOnAppRemoteNew onAppRemoteNew; void * onAppRemoteNewParam; ORTEOnAppDelete onAppDelete; void * onAppDeleteParam; ORTEOnPubRemote onPubRemoteNew; void * onPubRemoteNewParam; ORTEOnPubRemote onPubRemoteChanged; void * onPubRemoteChangedParam; ORTEOnPubDelete onPubDelete; void * onPubDeleteParam; ORTEOnSubRemote onSubRemoteNew;

Page 130: WP10 -D10.8 Programmer's Guide - MNIS

void * onSubRemoteNewParam; ORTEOnSubRemote onSubRemoteChanged; void * onSubRemoteChangedParam; ORTEOnSubDelete onSubDelete; void * onSubDeleteParam; };

Members

onMgrNew

new manager has been created

onMgrNewParam

user parameters for onMgrNew handler

onMgrDelete

manager has been deleted

onMgrDeleteParam

user parameters for onMgrDelete handler

onAppRemoteNew

new remote application has been registered

onAppRemoteNewParam

user parameters for onAppRemoteNew handler

onAppDelete

an application has been removed

onAppDeleteParam

user parameters for onAppDelete handler

onPubRemoteNew

new remote publication has been registered

onPubRemoteNewParam

user parameters for onPubRemoteNew handler

Page 131: WP10 -D10.8 Programmer's Guide - MNIS

onPubRemoteChanged

a remote publication's parameters has been changed

onPubRemoteChangedParam

user parameters for onPubRemoteChanged handler

onPubDelete

a publication has been deleted

onPubDeleteParam

user parameters for onPubDelete handler

onSubRemoteNew

a new remote subscription has been registered

onSubRemoteNewParam

user parameters for onSubRemoteNew handler

onSubRemoteChanged

a remote subscription's parameters has been changed

onSubRemoteChangedParam

user parameters for onSubRemoteChanged handler

onSubDelete

a publication has been deleted

onSubDeleteParam

user parameters for onSubDelete handler

Description

Prototypes of events handler fucntions can be found in file typedefs_api.h.

Page 132: WP10 -D10.8 Programmer's Guide - MNIS

8) struct ORTETasksProp

8.1) Name

struct ORTETasksProp -- ORTE task properties, not supported

8.2) Synopsis

struct ORTETasksProp { Boolean realTimeEnabled; int smtStackSize; int smtPriority; int rmtStackSize; int rmtPriority; };

8.3) Members

realTimeEnabled

not supported

smtStackSize

not supported

smtPriority

not supported

rmtStackSize

not supported

rmtPriority

Page 133: WP10 -D10.8 Programmer's Guide - MNIS

not supported

9) struct ORTEDomainProp

9.1) Name

struct ORTEDomainProp -- domain properties

9.2) Synopsis

struct ORTEDomainProp { ORTETasksProp tasksProp; ORTEIFProp * IFProp; //interface propertiesunsigned char IFCount; //count of interfacesORTEDomainBaseProp baseProp; ORTEDomainWireProp wireProp; ORTEMulticastProp multicast; //multicast properiesORTEPublProp publPropDefault; //default properties for a Publ/SubORTESubsPropsubsPropDefault; char * mgrs; //managerschar * keys; //keysIPAddress appLocalManager; //applicationschar * version; //string product versionint recvBuffSize; int sendBuffSize; };

9.3) Members

tasksProp

Page 134: WP10 -D10.8 Programmer's Guide - MNIS

task properties

IFProp

properties of network interfaces

IFCount

number of network interfaces

baseProp

base properties (see ORTEDomainBaseProp for details)

wireProp

wire properties (see ORTEDomainWireProp for details)

multicast

multicast properties (see ORTEMulticastProp for details)

publPropDefault

default properties of publiciations (see ORTEPublProp for details)

subsPropDefault

default properties of subscriptions (see ORTESubsProp for details)

mgrs

list of known managers

keys

access keys for managers

appLocalManager

IP address of local manager (default localhost)

version

string product version

Page 135: WP10 -D10.8 Programmer's Guide - MNIS

recvBuffSize

receiving queue length

sendBuffSize

transmitting queue length

a) Functions

Table of ContentsIPAddressToString -- converts IP address IPAddress to its string representation StringToIPAddress -- converts IP address from string into IPAddress NtpTimeToStringMs -- converts NtpTime to its text representation in milisecondsNtpTimeToStringUs -- converts NtpTime to its text representation inmicroseconds ORTEDomainStart -- start specific threads ORTEDomainPropDefaultGet -- returns default properties of a domain ORTEDomainInitEvents -- initializes list of events ORTEDomainAppCreate -- creates an application object within given domain ORTEDomainAppDestroy -- destroy Application object ORTEDomainAppSubscriptionPatternAdd -- create pattern-based subscription ORTEDomainAppSubscriptionPatternRemove -- remove subscription pattern ORTEDomainAppSubscriptionPatternDestroy -- destroys all subscriptionpatterns ORTEDomainMgrCreate -- create manager object in given domain ORTEDomainMgrDestroy -- destroy manager object ORTEPublicationCreate -- creates new publication ORTEPublicationDestroy -- removes a publication ORTEPublicationPropertiesGet -- read properties of a publication ORTEPublicationPropertiesSet -- set properties of a publication ORTEPublicationGetStatus -- removes a publication ORTEPublicationSend -- force publication object to issue new data ORTESubscriptionCreate -- adds a new subscription ORTESubscriptionDestroy -- removes a subscription ORTESubscriptionPropertiesGet -- get properties of a subscription ORTESubscriptionPropertiesSet -- set properties of a subscription ORTESubscriptionWaitForPublications -- waits for given number of publications ORTESubscriptionGetStatus -- get status of a subscription ORTESubscriptionPull -- read data from receiving buffer ORTETypeRegisterAdd -- register new data type ORTETypeRegisterDestroyAll -- destroy all registered data types ORTEVerbositySetOptions -- set verbosity options ORTEVerbositySetLogFile -- set log file ORTEInit -- initialization of ORTE layer (musi se zavolat) ORTEAppSendThread -- resume sending thread in context of calling function.

Page 136: WP10 -D10.8 Programmer's Guide - MNIS

ORTESleepMs -- suspends calling thread for given time

9.4) IPAddressToString

a) Name

IPAddressToString -- converts IP address IPAddress to its string representation

b) Synopsischar* IPAddressToString (IPAddress ipAddress, char * buff);

c) ArgumentsipAddress

source IP address

buff

output buffer

d) StringToIPAddress

Name

StringToIPAddress -- converts IP address from string into IPAddress

SynopsisIPAddress StringToIPAddress (const char * string);

Argumentsstring

source string

NtpTimeToStringMs

Name

NtpTimeToStringMs -- converts NtpTime to its text representation in miliseconds

Synopsis

char * NtpTimeToStringMs (NtpTime time, char * buff);

Page 137: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

time

time given in NtpTime structure

buff

output buffer

NtpTimeToStringUs

Name

NtpTimeToStringUs -- converts NtpTime to its text representation inmicroseconds

Synopsis

char * NtpTimeToStringUs (NtpTime time, char * buff);

Arguments

time

time given in NtpTime structure

buff

output buffer

ORTEDomainStart

Name

ORTEDomainStart -- start specific threads

Synopsis

void ORTEDomainStart (ORTEDomain * d, BooleanrecvMetatrafficThread, Boolean recvUserDataThread, BooleansendThread);

Arguments

d

domain object handle

recvMetatrafficThread

Page 138: WP10 -D10.8 Programmer's Guide - MNIS

specifies whether recvMetatrafficThread should be started (ORTE_TRUE)or remain suspended (ORTE_FALSE).

recvUserDataThread

specifies whether recvUserDataThread should be started (ORTE_TRUE) orremain suspended (ORTE_FALSE).

sendThread

specifies whether sendThread should be started (ORTE_TRUE) or remainsuspended (ORTE_FALSE).

Description

Functions ORTEDomainAppCreate and ORTEDomainMgrCreate providefacility to create an object with its threads suspended. Use functionORTEDomainStart to resume those suspended threads.

ORTEDomainPropDefaultGet

Name

ORTEDomainPropDefaultGet -- returns default properties of a domain

Synopsis

Boolean ORTEDomainPropDefaultGet (ORTEDomainProp * prop);

Arguments

prop

pointer to struct ORTEDomainProp

Description

Structure ORTEDomainProp referenced by prop will be filled by its defaultvalues. Returns ORTE_TRUE if successful or ORTE_FALSE in case of anyerror.

ORTEDomainInitEvents

Name

ORTEDomainInitEvents -- initializes list of events

Synopsis

Boolean ORTEDomainInitEvents (ORTEDomainAppEvents * events);

Page 139: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

events

pointer to struct ORTEDomainAppEvents

Description

Initializes structure pointed by events. Every member is set to NULL. ReturnsORTE_TRUE if successful or ORTE_FALSE in case of any error.

ORTEDomainAppCreate

Name

ORTEDomainAppCreate -- creates an application object within given domain

Synopsis

ORTEDomain * ORTEDomainAppCreate (int domain,ORTEDomainProp * prop, ORTEDomainAppEvents * events,Boolean suspended);

Arguments

domain

given domain

prop

properties of application

events

events associated with application or NULL

suspended

specifies whether threads of this application should be started as well(ORTE_FALSE) or stay suspended (ORTE_TRUE). SeeORTEDomainStart for details how to resume suspended threads

Description

Creates new Application object and sets its properties and events. Return handleto created object or NULL in case of any error.

Page 140: WP10 -D10.8 Programmer's Guide - MNIS

ORTEDomainAppDestroy

Name

ORTEDomainAppDestroy -- destroy Application object

Synopsis

Boolean ORTEDomainAppDestroy (ORTEDomain * d);

Arguments

d

domain

Description

Destroys all application objects in specified domain. Returns ORTE_TRUE orORTE_FALSE in case of any error.

ORTEDomainAppSubscriptionPatternAdd

Name

ORTEDomainAppSubscriptionPatternAdd -- create pattern-based subscription

Synopsis

Boolean ORTEDomainAppSubscriptionPatternAdd (ORTEDomain *d, const char * topic, const char * type,ORTESubscriptionPatternCallBack subscriptionCallBack, void* param);

Arguments

d

domain object

topic

pattern for topic

type

pattern for type

subscriptionCallBack

Page 141: WP10 -D10.8 Programmer's Guide - MNIS

pointer to callback function which will be called whenever any data arereceived through this subscription

param

user params for callback function

Description

This function is intended to be used in application interesded in more publisheddata from possibly more remote applications, which should be received throughsingle subscription. These different publications are specified by pattern given totopic and type parameters.

For example suppose there are publications of topics liketemperatureEngine1, temperatureEngine2,temperatureEngine1Backup and temperatureEngine2Backupsomewhere on our network. We can subscribe to each of Engine1 temperationsby creating single subscription with pattern for topic set to"temperatureEngine1*". Or, if we are interested only in values from backupmeasurements, we can use pattern "*Backup".

Syntax for patterns is the same as syntax for fnmatch function, which isemployed for pattern recognition.

Returns ORTE_TRUE if successful or ORTE_FALSE in case of any error.

ORTEDomainAppSubscriptionPatternRemove

Name

ORTEDomainAppSubscriptionPatternRemove -- remove subscription pattern

Synopsis

Boolean ORTEDomainAppSubscriptionPatternRemove (ORTEDomain* d, const char * topic, const char * type);

Arguments

d

domain handle

topic

pattern to be removed

type

pattern to be removed

Page 142: WP10 -D10.8 Programmer's Guide - MNIS

Description

Removes subscritions created byORTEDomainAppSubscriptionPatternAdd. Patterns for type and topicmust be exactly the same strings as whenORTEDomainAppSubscriptionPatternAdd function was called.

Returns ORTE_TRUE if successful or ORTE_FALSE if none matching recordwas found

ORTEDomainAppSubscriptionPatternDestroy

Name

ORTEDomainAppSubscriptionPatternDestroy -- destroys all subscriptionpatterns

Synopsis

Boolean ORTEDomainAppSubscriptionPatternDestroy (ORTEDomain* d);

Arguments

d

domain handle

Description

Destroys all subscription patterns which were specified previously byORTEDomainAppSubscriptionPatternAdd function.

Returns ORTE_TRUE if successful or ORTE_FALSE in case of any error.

ORTEDomainMgrCreate

Name

ORTEDomainMgrCreate -- create manager object in given domain

Synopsis

ORTEDomain * ORTEDomainMgrCreate (int domain,ORTEDomainProp * prop, ORTEDomainAppEvents * events,Boolean suspended);

Arguments

domain

-- undescribed --

Page 143: WP10 -D10.8 Programmer's Guide - MNIS

prop

desired manager's properties

events

manager's event handlers or NULL

suspended

specifies whether threads of this manager should be started as well(ORTE_FALSE) or stay suspended (ORTE_TRUE). SeeORTEDomainStart for details how to resume suspended threads

Description

Creates new manager object and sets its properties and events. Return handleto created object or NULL in case of any error.

ORTEDomainMgrDestroy

Name

ORTEDomainMgrDestroy -- destroy manager object

Synopsis

Boolean ORTEDomainMgrDestroy (ORTEDomain * d);

Arguments

d

manager object to be destroyed

Description

Returns ORTE_TRUE if successful or ORTE_FALSE in case of any error.

ORTEPublicationCreate

Name

ORTEPublicationCreate -- creates new publication

Synopsis

ORTEPublication * ORTEPublicationCreate (ORTEDomain * d,const char * topic, const char * typeName, void * instance,NtpTime * persistence, int strength, ORTESendCallBacksendCallBack, void * sendCallBackParam, NtpTime *sendCallBackDelay);

Page 144: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

d

pointer to application object

topic

name of topic

typeName

data type description

instance

output buffer where application stores data for publication

persistence

persistence of publication

strength

strength of publication

sendCallBack

pointer to callback function

sendCallBackParam

user parameters for callback function

sendCallBackDelay

periode for timer which issues callback function

Description

Creates new publication object with specified parameters. The sendCallBackfunction is called periodically with sendCallBackDelay periode. In strictreliable mode the sendCallBack function will be called only if there is enoughroom in transmitting queue in order to prevent any data loss. ThesendCallBack function should prepare data to be published by this publicationand place them into instance buffer.

Returns handle to publication object.

Page 145: WP10 -D10.8 Programmer's Guide - MNIS

ORTEPublicationDestroy

Name

ORTEPublicationDestroy -- removes a publication

Synopsis

int ORTEPublicationDestroy (ORTEPublication * cstWriter);

Arguments

cstWriter

handle to publication to be removed

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstWriter is notvalid cstWriter handle.

ORTEPublicationPropertiesGet

Name

ORTEPublicationPropertiesGet -- read properties of a publication

Synopsis

ORTEPublicationPropertiesGet (ORTEPublication * cstWriter,ORTEPublProp * pp);

Arguments

cstWriter

pointer to cstWriter object which provides this publication

pp

pointer to ORTEPublProp structure where values of publication's propertieswill be stored

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstWriter is notvalid cstWriter handle.

ORTEPublicationPropertiesSet

Name

ORTEPublicationPropertiesSet -- set properties of a publication

Page 146: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis

int ORTEPublicationPropertiesSet (ORTEPublication *cstWriter, ORTEPublProp * pp);

Arguments

cstWriter

pointer to cstWriter object which provides this publication

pp

pointer to ORTEPublProp structure containing values of publication'sproperties

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstWriter is notvalid publication handle.

ORTEPublicationGetStatus

Name

ORTEPublicationGetStatus -- removes a publication

Synopsis

int ORTEPublicationGetStatus (ORTEPublication * cstWriter,ORTEPublStatus * status);

Arguments

cstWriter

pointer to cstWriter object which provides this publication

status

pointer to ORTEPublStatus structure

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if happ is not validpublication handle.

ORTEPublicationSend

Name

ORTEPublicationSend -- force publication object to issue new data

Synopsis

int ORTEPublicationSend (ORTEPublication * cstWriter);

Page 147: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

cstWriter

publication object

Description

Returns ORTE_OK if successful.

ORTESubscriptionCreate

Name

ORTESubscriptionCreate -- adds a new subscription

Synopsis

ORTESubscription * ORTESubscriptionCreate (ORTEDomain * d,SubscriptionMode mode, SubscriptionType sType, const char *topic, const char * typeName, void * instance, NtpTime *deadline, NtpTime * minimumSeparation, ORTERecvCallBackrecvCallBack, void * recvCallBackParam);

Arguments

d

pointer to ORTEDomain object where this subscription will be created

mode

see enum SubscriptionMode

sType

see enum SubscriptionType

topic

name of topic

typeName

name of data type

instance

pointer to output buffer

deadline

Page 148: WP10 -D10.8 Programmer's Guide - MNIS

deadline

minimumSeparation

minimum time interval between two publications sent by Publisher asrequested by Subscriber (strict - minumSep musi byt 0)

recvCallBack

callback function called when new Subscription has been received or if anychange of subscription's status occures

recvCallBackParam

user parameters for recvCallBack

Description

Returns handle to Subscription object.

ORTESubscriptionDestroy

Name

ORTESubscriptionDestroy -- removes a subscription

Synopsis

int ORTESubscriptionDestroy (ORTESubscription * cstReader);

Arguments

cstReader

handle to subscriotion to be removed

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstReader is notvalid subscription handle.

ORTESubscriptionPropertiesGet

Name

ORTESubscriptionPropertiesGet -- get properties of a subscription

Synopsis

int ORTESubscriptionPropertiesGet (ORTESubscription *cstReader, ORTESubsProp * sp);

Arguments

cstReader

Page 149: WP10 -D10.8 Programmer's Guide - MNIS

handle to publication

sp

pointer to ORTESubsProp structure where properties of subscrition will bestored

ORTESubscriptionPropertiesSet

Name

ORTESubscriptionPropertiesSet -- set properties of a subscription

Synopsis

int ORTESubscriptionPropertiesSet (ORTESubscription *cstReader, ORTESubsProp * sp);

Arguments

cstReader

handle to publication

sp

pointer to ORTESubsProp structure containing desired properties of thesubscription

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstReader is notvalid subscription handle.

ORTESubscriptionWaitForPublications

Name

ORTESubscriptionWaitForPublications -- waits for given number of publications

Synopsis

int ORTESubscriptionWaitForPublications (ORTESubscription *cstReader, NtpTime wait, unsigned int retries, unsigned intnoPublications);

Arguments

cstReader

handle to subscription

wait

Page 150: WP10 -D10.8 Programmer's Guide - MNIS

time how long to wait

retries

number of retries if specified number of publications was not reached

noPublications

desired number of publications

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstReader is notvalid subscription handle or ORTE_TIMEOUT if number of retries has beenexhausted..

ORTESubscriptionGetStatus

Name

ORTESubscriptionGetStatus -- get status of a subscription

Synopsis

int ORTESubscriptionGetStatus (ORTESubscription *cstReader, ORTESubsStatus * status);

Arguments

cstReader

handle to subscription

status

pointer to ORTESubsStatus structure

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstReader is notvalid subscription handle.

ORTESubscriptionPull

Name

ORTESubscriptionPull -- read data from receiving buffer

Synopsis

int ORTESubscriptionPull (ORTESubscription * cstReader);

Arguments

cstReader

Page 151: WP10 -D10.8 Programmer's Guide - MNIS

handle to subscription

Description

Returns ORTE_OK if successful or ORTE_BAD_HANDLE if cstReader is notvalid subscription handle.

ORTETypeRegisterAdd

Name

ORTETypeRegisterAdd -- register new data type

Synopsis

int ORTETypeRegisterAdd (ORTEDomain * d, const char *typeName, ORTETypeSerialize ts, ORTETypeDeserialize ds,unsigned int gms);

Arguments

d

domain object handle

typeName

name of data type

ts

pointer to serialization function. If NULL data will be copied without anyprocessing.

ds

deserialization function. If NULL data will be copied without any processing.

gms

maximum length of data (in bytes)

Description

Each data type has to be registered. Main purpose of this process is to defineserialization and deserialization functions for given data type. The same datatype can be registered several times, previous registrations of the same type willbe overwritten.

Examples of serialization and deserialization functions can be found ifcontrib/shape/ortedemo_types.c file.

Returns ORTE_OK if new data type has been succesfully registered.

Page 152: WP10 -D10.8 Programmer's Guide - MNIS

ORTETypeRegisterDestroyAll

Name

ORTETypeRegisterDestroyAll -- destroy all registered data types

Synopsis

int ORTETypeRegisterDestroyAll (ORTEDomain * d);

Arguments

d

domain object handle

Description

Destroys all data types which were previously registered by functionORTETypeRegisterAdd.

Return ORTE_OK if all data types has been succesfully destroyed.

ORTEVerbositySetOptions

Name

ORTEVerbositySetOptions -- set verbosity options

Synopsis

void ORTEVerbositySetOptions (const char * options);

Arguments

options

verbosity options

Description

There are 10 levels of verbosity ranging from 1 (lowest) to 10 (highest). It ispossible to specify certain level of verbosity for each module of ORTE library.List of all supported modules can be found in linorte/usedSections.txt file. Everymodule has been aasigned with a number as can be seen in usedSections.txtfile.

For instance

options = "ALL,7" Verbosity will be set to level 7 for all modules.

options = "51,7:32,5" Modules 51 (RTPSCSTWrite.c) will use verbosity level 7and module 32 (ORTEPublicationTimer.c) will use verbosity level 5.

Page 153: WP10 -D10.8 Programmer's Guide - MNIS

Maximum number of modules and verbosity levels can be changed in order tosave some memory space if small memory footprint is neccessary. These valuesare defined as macros MAX_DEBUG_SECTIONS and MAX_DEBUG_LEVEL infile include/defines.h.

Return ORTE_OK if desired verbosity levels were successfuly set.

ORTEVerbositySetLogFile

Name

ORTEVerbositySetLogFile -- set log file

Synopsis

void ORTEVerbositySetLogFile (const char * logfile);

Arguments

logfile

log file name

Description

Sets output file where debug messages will be writen to. By default thesemessages are written to stdout.

ORTEInit

Name

ORTEInit -- initialization of ORTE layer (musi se zavolat)

Synopsis

void ORTEInit ( void);

Arguments

void

no arguments

ORTEAppSendThread

Name

ORTEAppSendThread -- resume sending thread in context of calling function.

Synopsis

void ORTEAppSendThread (ORTEDomain * d);

Arguments

d

Page 154: WP10 -D10.8 Programmer's Guide - MNIS

domain object handle

Description

Sending thread will be resumed. This function never returns.

ORTESleepMs

Name

ORTESleepMs -- suspends calling thread for given time

Synopsis

void ORTESleepMs (unsigned int ms);

Arguments

ms

miliseconds to sleep

Macros

Table of ContentsSeqNumberCmp -- comparison of two sequence numbers SeqNumberInc -- incrementation of a sequence number SeqNumberAdd -- addition of two sequential numbers SeqNumberDec -- decrementation of a sequence number SeqNumberSub -- substraction of two sequential numbers NtpTimeCmp -- comparation of two NtpTimes NtpTimeAdd -- addition of two NtpTimes NtpTimeSub -- substraction of two NtpTimes NtpTimeAssembFromMs -- converts seconds and miliseconds to NtpTime NtpTimeDisAssembToMs -- converts NtpTime to seconds and miliseconds NtpTimeAssembFromUs -- converts seconds and useconds to NtpTime NtpTimeDisAssembToUs -- converts NtpTime to seconds and useconds Domain2Port -- converts Domain value to IP Port value Domain2PortMulticastUserdata -- converts Domain value to userdata IP Portvalue Domain2PortMulticastMetatraffic -- converts Domain value to metatraffic IP Portvalue

SeqNumberCmp

Name

SeqNumberCmp -- comparison of two sequence numbers

Synopsis

SeqNumberCmp ( sn1, sn2);

Page 155: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

sn1

source sequential number 1

sn2

source sequential number 2

Return

1 if sn1 > sn2 -1 if sn1 < sn2 0 if sn1 = sn2

SeqNumberInc

Name

SeqNumberInc -- incrementation of a sequence number

Synopsis

SeqNumberInc ( res, sn);

Arguments

res

result

sn

sequential number to be incremented

Description

res = sn + 1

SeqNumberAdd

Name

SeqNumberAdd -- addition of two sequential numbers

Synopsis

SeqNumberAdd ( res, sn1, sn2);

Arguments

res

result

sn1

Page 156: WP10 -D10.8 Programmer's Guide - MNIS

source sequential number 1

sn2

source sequential number 2

Description

res = sn1 + sn2

SeqNumberDec

Name

SeqNumberDec -- decrementation of a sequence number

Synopsis

SeqNumberDec ( res, sn);

Arguments

res

result

sn

sequential number to be decremented

Description

res = sn - 1

SeqNumberSub

Name

SeqNumberSub -- substraction of two sequential numbers

Synopsis

SeqNumberSub ( res, sn1, sn2);

Arguments

res

result

sn1

source sequential number 1

Page 157: WP10 -D10.8 Programmer's Guide - MNIS

sn2

source sequential number 2

Description

res = sn1 - sn2

NtpTimeCmp

Name

NtpTimeCmp -- comparation of two NtpTimes

Synopsis

NtpTimeCmp ( time1, time2);

Arguments

time1

source time 1

time2

source time 2

Return value

1 if time 1 > time 2 -1 if time 1 < time 2 0 if time 1 = time 2

NtpTimeAdd

Name

NtpTimeAdd -- addition of two NtpTimes

Synopsis

NtpTimeAdd ( res, time1, time2);

Arguments

res

result

time1

source time 1

time2

Page 158: WP10 -D10.8 Programmer's Guide - MNIS

source time 2

Description

res = time1 + time2

NtpTimeSub

Name

NtpTimeSub -- substraction of two NtpTimes

Synopsis

NtpTimeSub ( res, time1, time2);

Arguments

res

result

time1

source time 1

time2

source time 2

Description

res = time1 - time2

NtpTimeAssembFromMs

Name

NtpTimeAssembFromMs -- converts seconds and miliseconds to NtpTime

Synopsis

NtpTimeAssembFromMs ( time, s, msec);

Arguments

time

time given in NtpTime structure

s

seconds portion of given time

Page 159: WP10 -D10.8 Programmer's Guide - MNIS

msec

miliseconds portion of given time

NtpTimeDisAssembToMs

Name

NtpTimeDisAssembToMs -- converts NtpTime to seconds and miliseconds

Synopsis

NtpTimeDisAssembToMs ( s, msec, time);

Arguments

s

seconds portion of given time

msec

miliseconds portion of given time

time

time given in NtpTime structure

NtpTimeAssembFromUs

Name

NtpTimeAssembFromUs -- converts seconds and useconds to NtpTime

Synopsis

NtpTimeAssembFromUs ( time, s, usec);

Arguments

time

time given in NtpTime structure

s

seconds portion of given time

usec

microseconds portion of given time

Page 160: WP10 -D10.8 Programmer's Guide - MNIS

NtpTimeDisAssembToUs

Name

NtpTimeDisAssembToUs -- converts NtpTime to seconds and useconds

Synopsis

NtpTimeDisAssembToUs ( s, usec, time);

Arguments

s

seconds portion of given time

usec

microseconds portion of given time

time

time given in NtpTime structure

Domain2Port

Name

Domain2Port -- converts Domain value to IP Port value

Synopsis

Domain2Port ( d, p);

Arguments

d

domain

p

port

Domain2PortMulticastUserdata

Name

Domain2PortMulticastUserdata -- converts Domain value to userdata IP Portvalue

Synopsis

Domain2PortMulticastUserdata ( d, p);

Page 161: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

d

domain

p

port

Domain2PortMulticastMetatraffic

Name

Domain2PortMulticastMetatraffic -- converts Domain value to metatraffic IP Portvalue

Synopsis

Domain2PortMulticastMetatraffic ( d, p);

Arguments

d

domain

p

port

ORTE Implementation Issues

ORTE is network middleware for distributed, real-time application developmentthat uses the real-time, publish-subscribe model. The middleware is available fora variety of platforms including RTAI, RTLinux, Windows, and a several versionsof Unix. The compilation system is mainly based on autoconf.

ORTE is middleware composed of a database, and tasks. On the top of ORTEarchitecture is application interface (API). By using API users should write selfapplication. The tasks perform all of the message addressingserialization/deserialization, and transporting. The ORTE components are shownin Figure 1-5

Figure 1-5. ORTE Architecture

The RTPS protocol defines two kinds of Applications:

• Manager: The manager is a special Application that helps applicationsautomatically discover each other on the Network.

Page 162: WP10 -D10.8 Programmer's Guide - MNIS

• ManagedApplication: A ManagedApplication is an Application that ismanaged by one or more Managers. Every ManagedApplication ismanaged by at least one Manager.

The manager is mostly designed like separate application. In RTPS architectureis able to create application which contains manager and managedapplication,but for easy managing is better split both. The ORTE contains a separateinstance of manager located in directory orte/manager.

The manager is composed from five kinds of objects:

• WriterApplicationSelf: through which the Manager provides informationabout its own parameters to Managers on other nodes.

• ReaderManagers: CSTReader through which the Manager obtainsinformation on the state of all other Managers on the Network.

• ReaderApplications: CSTReader which is used for the registration oflocal and remote managedApplications.

• WriterManagers: CSTWriter through which the Manager will send thestate of all Managers in the Network to all its managees.

• WriterApplications: CSTWriter through which the Manager will sendinformation about its managees to other Managers in the Network.

A Manager that discovers a new ManagedApplication through itsreaderApplications must decide whether it must manage thisManagedApplication or not. For this purpose, the attribute managerKeyList of theApplication is used. If one of the ManagedApplication's keys (in the attributemanagerKeyList) is equal to one of the Manager's keys, the Manager acceptsthe Application as a managee. If none of the keys are equal, the managedapplication is ignored. At the end of this process all Managers have discoveredtheir managees and the ManagedApplications know all Managers in theNetwork.

The managedApplication is composed from seven kinds of objects:

• WriterApplicationSelf: a CSTWriter through which theManagedApplication registers itself with the local Manager.

• ReaderApplications: a CSTReader through which theManagedApplication receives information about anotherManagedApplications in the network.

• ReaderManagers: a CSTReader through which the ManagedApplicationreceives information about Managers.

• WriterPublications: CSTWriter through which the Manager will send thestate of all Managers in the Network to all its managees.

• ReaderPublications: a Reader through which the Publication receivesinformation about Subscriptions.

• WriterSubscriptions: a Writer that provides information aboutSubscription to Publications.

Page 163: WP10 -D10.8 Programmer's Guide - MNIS

• ReaderSubscriptions: a Reader that receives issues from one or moreinstances of Publication, using the publish-subscribe service.

The ManagedApplication has a special CSTWriter writerApplicationSelf. TheComposite State (CS) of the ManagedApplication's writerApplicationSelf objectcontains only one NetworkObject - the application itself. ThewriterApplicationSelf of the ManagedApplication must be configured to announceits presence repeatedly and does not request nor expect acknowledgments.

The ManagedApplications now use the CST Protocol between thewriterApplications of the Managers and the readerApplications of theManagedApplications in order to discover other ManagedApplications in theNetwork. Every ManagedApplication has two special CSTWriters,writerPublications and writerSubscriptions, and two special CSTReaders,readerPublications and readerSubscriptions.

Once ManagedApplications have discovered each other, they use the standardCST protocol through these special CSTReaders and CSTWriter to transfer theattributes of all Publications and Subscriptions in the Network.

The ORTE stores all data in local database per application. There isn't centralstore where are data saved. If an application comes into communication, thanwill be created local mirror of all applications parameters. Parts of internalstructures are shown in Figure 1-6.

Figure 1-6. ORTE Internal Attributes

Following example shows communication between two nodes (N1, N2). Thereare applications running on each node - MA1.2 on node N1 and MA2.1, MA2.2on node N2. Each node has it own manager (M1, M2). The example shows,what's happen when a new application comes into communication (MA1.1).

1. MA1.1 introduces itself to local manager M1

2. M1 sends back list of remote managers Mx and other local applications MA1.x

3. MA1.1 is introduced to all Mx by M1

4. All remote MAs are reported now to M1.1

5. MA1.1 is queried for self services (publishers and subscriberes) from othersMAx.

6. MA1.1 asks for services to others MAx.

7. All MAs know information about others.

The corresponding publishers and subscribers with matching Topic and Type areconnected and starts their data communication.

Figure 1-7. RTPS Communication among Network Objects

ORTE Examples

This chapter expect that you are familiar with RTPS communication architecturedescribed in the Section called ORTE Description .

Page 164: WP10 -D10.8 Programmer's Guide - MNIS

Publications can offer multiple reliability policies ranging from best-efforts to strict(blocking) reliability. Subscription can request multiple policies of desiredreliability and specify the relative precedence of each policy. Publications willautomatically select among the highest precedence requested policy that isoffered by the publication.

• BestEffort: This reliability policy is suitable for data that are sending witha period. There are no message resending when a message is lost. Onother hand, this policy offer maximal predictable behaviour. For instance,consider a publication which send data from a sensor (pressure,temperature, ...).

Figure 1-8. Periodic Snapshots of a BestEffort Publisher

• StrictReliable: The ORTE supports the reliable delivery of issues. Thiskind of communication is used where a publication want to be sure that alldata will be delivered to subscriptions. For instance, consider a publicationwhich send commands.

Command data flow requires that each instruction in the sequence isdelivered reliably once and only once. Commands are often not timecritical.

BestEffort Communication

Before creating a Publication or Subscription is necessary to create a domain byusing function ORTEDomainAppCreate. The code should looks like:

int main(int argc, char *argv[]) { ORTEDomain *d = NULL; ORTEBoolean suspended= ORTE_FALSE;

ORTEInit();

d = ORTEDomainAppCreate(ORTE_DEFAUL_DOMAIN, NULL, NULL, suspended); if (!d) { printf("ORTEDomainAppCreate failed\n"); return -1; }}

The ORTEDomainAppCreate allocates and initializes resources that are neededfor communication. The parameter suspended says if ORTEDomain takessuspend communicating threads. In positive case you have to start threadsmanually by using ORTEDomainStart.

Next step in creation of a application is registration serialization anddeserialization routines for the specific type. You can't specify this functions, butthe incoming data will be only copied to output buffer.

Page 165: WP10 -D10.8 Programmer's Guide - MNIS

ORTETypeRegisterAdd(d, "HelloMsg", NULL, NULL, 64);

To create a publication in specific domain use the functionORTEPublicationCreate.

char instance2send[64];NtpTime persistence, delay;

NTPTIME_BUILD(persistence, 3); /* this issue is valid for 3 seconds */NTPTIME_DELAY(delay, 1); /* a callback function will be calledevery 1 second */p = ORTEPublicationCreate( d, "Example HelloMsg", "HelloMsg", &instance2Send, &persistence, 1, sendCallBack, NULL, &delay);

The callback function will be then called when a new issue from publisher has tobe sent. It's the case when you specify callback routine inORTEPublicationCreate. When there isn't a routine you have to send datamanually by call function ORTEPublicationSend. This option is useful forsending periodic data.

void sendCallBack(const ORTESendInfo *info, void *vinstance, void*sendCallBackParam){ char *instance = (char *) vinstance; switch (info->status) { case NEED_DATA: printf("Sending publication, count %d\n", counter); sprintf(instance, "Hello world (%d)", counter++); break;

case CQL: //criticalQueueLevel has been reached break; }}

Subscribing application needs to create a subscription with publication's Topicand TypeName. A callback function will be then called when a new issue frompublisher will be received.

ORTESubscription *s;NtpTime deadline, minimumSeparation;

Page 166: WP10 -D10.8 Programmer's Guide - MNIS

NTPTIME_BUILD(deadline, 20); NTPTIME_BUILD(minimumSeparation, 0); p = ORTESubscriptionCreate( d, IMMEDIATE, BEST_EFFORTS, "Example HelloMsg", "HelloMsg", &instance2Recv, &deadline, &minimumSeparation, recvCallBack, NULL);

The callback function is shown in the following example:

void recvCallBack(const ORTERecvInfo *info, void *vinstance, void*recvCallBackParam){ char *instance = (char *) vinstance; switch (info->status) { case NEW_DATA: printf("%s\n", instance); break;

case DEADLINE: //deadline occurred break; }}

Similarly examples are located in ORTE subdirectory orte/examples/hello.There are demonstrating programs how to create an application which willpublish some data and another application, which will subscribe to thispublication.

Reliable communication

The reliable communication is used especially in situations where we needguarantee data delivery. The ORTE supports the inorder delivery of issues withbuilt-in retry mechanism

The creation of reliable communication starts like besteffort communication.Difference is in creation a subscription. Third parameter is just only changed toSTRICT_RELIABLE.

ORTESubscription *s;NtpTime deadline, minimumSeparation;

Page 167: WP10 -D10.8 Programmer's Guide - MNIS

NTPTIME_BUILD(deadline, 20); NTPTIME_BUILD(minimumSeparation, 0); p = ORTESubscriptionCreate( d, IMMEDIATE, STRICT_RELIABLE, "Example HelloMsg", "HelloMsg", &instance2Recv, &deadline, &minimumSeparation, recvCallBack, NULL);

Note:

Strict reliable subscription must set minimumSeparation to zero! The middlewarecan't guarantee that the data will be delivered on first attempt (retry mechanism).

Sending of a data is blocking operation. It's strongly recommended to setupsending queue to higher value. Default value is 1.

ORTEPublProp *pp; ORTEPublicationPropertiesGet(publisher,pp);pp->sendQueueSize=10;pp->criticalQueueLevel=8;ORTEPublicationPropertiesSet(publisher,pp);

An example of reliable communication is in ORTE subdirectoryorte/examples/reliable. There are located a strictreliable subscription andpublication.

Serialization/Deserialization

Actually the ORTE doesn't support any automatic creation ofserialization/deserializaction routines. This routines have to be designedmanually by the user. In next is shown, how should looks both for the structureBoxType.

typedef struct BoxType { int32_t color; int32_t shape;} BoxType;

voidBoxTypeSerialize(ORTECDRStream *cdr_stream, void *instance) { BoxType *boxType=(BoxType*)instance;

*(int32_t*)cdr_stream->bufferPtr=boxType->color; cdr_stream->bufferPtr+=sizeof(int32_t); *(int32_t*)cdr_stream->bufferPtr=boxType->shape; cdr_stream->bufferPtr+=sizeof(int32_t);

Page 168: WP10 -D10.8 Programmer's Guide - MNIS

}

voidBoxTypeDeserialize(ORTECDRStream *cdr_stream, void *instance) { BoxType *boxType=(BoxType*)instance;

boxType->color=*(int32_t*)cdr_stream->bufferPtr; cdr_stream->bufferPtr+=sizeof(int32_t); boxType->shape=*(int32_t*)cdr_stream->bufferPtr; cdr_stream->bufferPtr+=sizeof(int32_t);}

When we have written a serialization/deserialization routine we need to registerthis routines to midleware by function ORTETypeRegisterAdd

ORTETypeRegisterAdd( domain, "BoxType", BoxTypeSerialize, BoxTypeDeserialize, sizeof(BoxType));

The registration must be called before creation a publication or subscription.Normally is ORTETypeRegisterAdd called immediately after creation of adomain (ORTEDomainCreate).

All of codes are part of the Shapedemo located in subdirectoryorte/contrib/shape.

ORTE Tests

There were not any serious tests performed yet. Current version has beenintensively tested against reference implementation of the protocol. Results ofthese test indicate that ORTE is fully interoperable with implementation providedby another vendor.

ORTE Usage Information

Installation and Setup

In this chapter is described basic steps how to makes installation and setupprocess of the ORTE. The process includes next steps:

1. Downloading the ORTE distribution

2. Compilation

3. Installing the ORTE library and utilities

4. Testing the installation

Page 169: WP10 -D10.8 Programmer's Guide - MNIS

Note:

On windows systems we are recommend to use Mingw or Cygwin systems. TheORTE support also MSVC compilation, but this kind of installation is notdescribed here.

Downloading

The ORTE component can be obtained from OCERA SourceForge web page(http://www.sf.net/projects/ocera/). Here is the component located also in selfdistribution branch as well as in OCERA distribution. Before developing anyapplication check if there is a new file release.

The CVS version of ORTE repository can be checked out be anonymous(pserver) CVS with the following commands.

cvs -d:pserver:[email protected]:/cvsroot/ocera logincvs -z3 -d:pserver:[email protected]:/cvsroot/oceraco ocera/components/comm/eth/orte/

Attention, there is developing version and can't be stable!

Compilation

Before the compilation process is necessary to prepare the source. Create a newdirectory for ORTE distribution. We will assume name of this directory /orte forLinux case. Copy or move downloaded ORTE sources to /orte (assume thename of sources orte-0.2.3.tar.gz). Untar and unzip this files by using nextcommands:

gunzip orte-0.2.3.tar.gztar xvf orte-0.2.3.tar

Now is the source prepared for compilation. Infrastructure of the ORTE isdesigned to support GNU make (needs version 3.81) as well as autoconfcompilation. In next we will continue with description of autoconf compilation,which is more general. The compilation can follows with commands:

mkdir buildcd build../configuremake

This is the case of outside autoconf compilation. In directory build are allchanges made over ORTE project. The source can be easy move to originalstate be removing of directory build.

Page 170: WP10 -D10.8 Programmer's Guide - MNIS

Installing

The result of compilation process are binary programs and ORTE library. For thenext developing is necessary to install this result. It can be easy done be typing:

make install

All developing support is transferred into directories with direct access of designtools.

name target pathortemanager, orteping,ortespy

/usr/local/bin

library /usr/local/libinclude /usr/local/includeThe installation prefix /usr/local/ can be changed during configuration. Usecommand ../configure --help for check more autoconf options.

Testing the Installation

To check of correct installation of ORTE open three shells.

1. In first shell type

ortemanager

2. In second shell type

orteping -s

This command will invoked creation of a subscription. You should see:

deadline occurreddeadline occurred...

3. In third shell type

orteping -p

This command will invoked creation of a publication. You should see:

sent issue 1sent issue 2sent issue 3sent issue 4...

Page 171: WP10 -D10.8 Programmer's Guide - MNIS

If the ORTE installation is properly, you will see incoming messages in secondshell (orteping -s).

received fresh issue 1received fresh issue 2received fresh issue 3received fresh issue 4...

It's sign, that communication is working correctly.

The ORTE Manager

A manager is special application that helps applications automatically discovereach other on the Network. Each time an object is created or destroyed, themanager propagate new information to the objects that are internally registered.

Every application precipitate in communication is managed by least onemanager. The manager should be designed like separated application as well aspart of designed application.

Figure 1-9. Position of Managers in RTPS communication

The ORTE provides one instance of a manager. Name of this utility isortemanager and is located in directory orte/ortemanager. Normally isnecessary to start ortemanager manually or use a script on UNIX systems. ForMandrake and Red-hat distribution is this script created in subdirectory rc.Windows users can install ortemanager like service by using option /install_service.

Note:

Don't forget to run a manager (ortemanager) on each RTPS participate node.During live of applications is necessary to be running this manager.

Example of Usage ortemanager

Table of Contentsortemanager -- the utility for discovery others applications and managers on thenetwork

Each manager has to know where are other managers in the network. Their IPaddresses are therefore specified as IPAddressX parameters of ortemanager. Allmanagers participate in one kind of communication use the same domainnumber. The domain number is transferred to port number by equation definedin RTPS specification (normally domain 0 is transferred to 7400 port).

Let's want to distribute the RTPS communication of nodes with IP addresses192.168.0.2 and 192.168.0.3. Private IP address is 192.168.0.1. Theortemanager can be execute with parameters:

Page 172: WP10 -D10.8 Programmer's Guide - MNIS

ortemanager -p 192.168.0.2:192.168.0.3

To communicate in different domain use (parameter -d):

ortemanager -d 1 -p 192.168.0.2:192.168.0.3

Very nice feature of ortemanager is use event system to inform ofcreation/destruction objects (parameter -e).

ortemanager -e -p 192.168.0.2:192.168.0.3

Now, you can see messages:

[smolik@localhost smolik]$ortemanager -e -p 192.168.0.2:192.168.0.3manager 0xc0a80001-0x123402 was acceptedapplication 0xc0a80002-0x800301 was acceptedapplication 0xc0a80002-0x800501 was acceptedapplication 0xc0a80002-0x800501 was deletedmanager 0xc0a80001-0x123402 was deleted

ortemanager

Name

ortemanager -- the utility for discovery others applications and managers on thenetwork

Synopsis

ortemanager [-d domain] [-p ip addresses] [-k ip addresses] [-Rrefresh] [-P purge] [-D ] [-E expiration] [-e ] [-v verbosity] [-lfilename] [-V] [-h]

Description

Main purpose of the utility ortemanager is debug and test ORTEcommunication.

OPTIONS

-d --domain

The number of working ORTE domain. Default is 0.

-p --peers

The IP addresses parsipiates in RTPS communication. See the Sectioncalled The ORTE Manager in Chapter 1 for example of usage.

-R --refresh

Page 173: WP10 -D10.8 Programmer's Guide - MNIS

The refresh time in manager. Default 60 seconds.

-P --purge

The searching time in local database for finding expired application. Default60 seconds.

-E --expiration

Expiration time in other applications.

-m --minimumSeparation

The minimum time between two issues.

-v --verbosity

Set verbosity level.

-l --logfile

All debug messages can be redirect into specific file.

-V --version

Print the version of ortemanager.

-h --help

Print usage screen.

Simple Utilities

Table of Contentsorteping -- the utility for debugging and testing of ORTE communicationortespy -- the utility for monitoring of ORTE issues

The simple utilities can be found in the orte/examples subdirectory of theORTE source subtree. These utilities are useful for testing and monitoring RTPScommunication.

The utilities provided directly by ORTE are:

orteping

the utility for easy creating of publications and subscriptions.

Page 174: WP10 -D10.8 Programmer's Guide - MNIS

ortespy

monitors issues produced by other application in specific domain.

orteping

Name

orteping -- the utility for debugging and testing of ORTE communication

Synopsis

orteping [-d domain] [-p ] [-S strength] [-D delay] [-s ] [-R refresh][-P purge] [-E expiration] [-m minimumSeparation] [-v verbosity][-q ] [-l filename] [-V] [-h]

Description

Main purpose of the utility orteping is debug and test ORTE communication.

OPTIONS

-d --domain

The number of working ORTE domain. Default is 0.

-p --publisher

Create a publisher with Topic - Ping and Type - PingData. The publisherwill publish a issue with period by parameter delay.

-s --strength

Setups relative weight against other publishers. Default is 1.

-D --delay

The time between two issues. Default 1 second.

-s --subscriber

Create a subscriber with Topic - Ping and Type - PingData.

-R --refresh

The refresh time in manager. Default 60 seconds.

-P --purge

Page 175: WP10 -D10.8 Programmer's Guide - MNIS

The searching time in local database for finding expired application. Default60 seconds.

-E --expiration

Expiration time in other applications.

-m --minimumSeparation

The minimum time between two issues.

-v --verbosity

Set verbosity level.

-q --quite

Nothing messages will be printed on screen. It can be useful for testingmaximal throughput.

-l --logfile

All debug messages can be redirect into specific file.

-V --version

Print the version of orteping.

-h --help

Print usage screen.

ortespy

Name

ortespy -- the utility for monitoring of ORTE issues

Synopsis

orteping [-d domain] [-v verbosity] [-R refresh] [-P purge] [-eexpiration] [-l filename] [-V] [-h]

Description

Main purpose of the utility ortespy is monitoring data traffic between publicationsand subscriptions.

Page 176: WP10 -D10.8 Programmer's Guide - MNIS

OPTIONS

-d --domain

The number of working ORTE domain. Default is 0.

-v --verbosity

Set verbosity level.

-R --refresh

The refresh time in manager. Default 60 seconds.

-P --purge

Create publisher

-e --expiration

Expiration time in other applications.

-l --logfile

All debug messages can be redirect into specific file.

-V --version

Print the version of orteping.

-h --help

Print usage screen.

Page 177: WP10 -D10.8 Programmer's Guide - MNIS

IX) Fault-Tolerancecomponents

by A. Lanusse and P. Vanuxeem

1) Degraded Mode Management

1.1) Description

The Degraded Mode Management Framework has been designed to offertransparent management of dynamic reconfiguration of applications on detectionof faulty situations.

Continuity of service is maintained in case of partial failure through gracefuldegradation management. The Degraded Mode Management Framework offersan integrated set of tools and components.

Design/build tool. The Ftbuilder permits the specification of application real-time constraints, different possible application modes along with relatedtransition conditions.

From this specification, code generation is achieved in order to instantiateinternal control data-bases of run-time components (ftappmon and ftcontroller)and to provide application model files.

Page 178: WP10 -D10.8 Programmer's Guide - MNIS

ftappmon . The ftappmon component is devoted to global application handling.It is in charge of overall application setup and of reconfiguration decisions. Itcontains information on different possible application modes and on transitionconditions. When an error is detected and notified by the ftcontroller, theftappmon analyzes the event and issues reconfiguration orders (stop, awake,switch ft-task behavior) towards the ftcontroller.

ftcontroller . The ftcontroller is in charge of the direct control of applicationthreads. It provides error detection (kill or timing error) and notification (towardsftappmon) and executes reconfiguration orders at task level.

API. A specific but reduced API has been defined for manipulating so called ft-tasks. Threemain functions: ft_task_init(), ft_task_create, ft_task_end(). These ft-tasks are actuallyencapsulation of periodic RTLinux tasks. Other functions are used to init internal data-bases.Besides these specific functions , application developers can use any RTLinux programmingfeature.

The framework currently available relies on a simplified model of applications.According to this model only simple applications with periodic tasks are handledat the moment. Though these are indeed quite restrictive hypotheses, theyrepresent a large range of effective current real-time embedded applications.Please refer to users's guide for the description of the main characteristics ofapplications handled and restrictions to applicability.

1.2) Usage

Degraded Mode Management configuration process takes three steps:

1. OS Type Selection : Soft and Hard real-time must be chosen and some sub-options must be checked (see below).

2. Components Selection : FT components + Hard Realtime + Degraded ModeManagement.

3. Core kernel Scheduling features selection : Priority or EDF scheduling.Only EDF scheduling will offer support for deadline miss detection.

1. OS-Type Selection

FT Degraded Mode Management support requires the selection of Hard and Softreal-time in the OS type section. This enables hard-realtime standard RTLinuxconfiguration options.

General dependencies of FT components are illustrated in the following figure.

Page 179: WP10 -D10.8 Programmer's Guide - MNIS

Required options are : loadable module support, RT-Linux support includingPOSIX Signals and POSIX Timers, Shared Memory support, POSIX TraceSupport in RTLinux., BigPhysarea support.

Note that POSIX Trace Support is mandatory for FT Degraded ModeManagement components.

Power Management support should not be selected.

Normally all these options are posted correctly in the standard OCERAdistribution, so just check.

2. FT Degraded Mode management components selection

FT components for degraded Mode Management have to be selected. If youselect the Framework, these are set automatically, just verify. Two componentsare necessary, the FT Controller and the FT Application Monitor, they must beselected together. At compilation time they will be merged into one single modulenamed ftappmonctrl.

Figure 1.1 : FT Degraded Mode Management Configuration step1

Page 180: WP10 -D10.8 Programmer's Guide - MNIS

The FTController is selected.

The FT Application Monitor is selected.

Figure 1.2 : FT Degraded Mode Management Configuration step2

Page 181: WP10 -D10.8 Programmer's Guide - MNIS

3. Core kernel Scheduling features selection

The last configuration step concerns the choice of scheduling policy. Thefunctioning of the Degraded Mode Management can follow several types ofscheduling, the facilities offered will depend on the choice done at configuration.

The error detection mechanism can handle two types of errors:

• Pthread_kill detection works with priority based or EDF scheduling policies;

• Timing errors (deadline miss) detection can only be detected if EDFscheduling is selected and related option Dealline Miss Detection.

Remark: Once a scheduling policy has been chosen during the configuration allthe ft_tasks will be scheduled according to this policy.

Priority based scheduling

Standard prioity based scheduling can be configured by selecting theApplication defined scheduler option in the the Scheduling section of theRTLinux Hard real-time part as indicated bellow. In this case the only type oferrors to be detected are Pthread-kill events.

The Application defined scheduler component provides support for severaltypes of scheduling policies defined above the RTLinux kernel itself. By default,the scheduling policy is based on priorities, which is the configuration that wemust use in this case. For further details see section Scheduling.

EDF scheduling

Figure 1.3 : FT Degraded Mode Management Configuration step3 – Priority scheduler

Page 182: WP10 -D10.8 Programmer's Guide - MNIS

This version of scheduling is implemented directly at RTLinux kernel level andnot above as it is the case with the Application Defined scheduler.

So if you want to detect both timing errors and pthread_kill events, you shouldselect EDF + Deadline-miss detection, as shown hereunder.

Remark: If you select only EDF, scheduling policy applied will be EDF but onlypthread_kill events will be detected, there will be no emission of Deadline-missevent.

The configuration EDF scheduling with Deadline-miss detection (DLM) is still anexperimental functionality. For the moment, support for EDF+DLM+SRP is notoffered.

1.3) Programming Interface (API)

The ftappmon component offers to the application developer an applicationprogramming interface, named FT-API, that is restricted to very few functionsft_task_init(), ft_task_create(), ft_task_end().

It offers also some additional FT-API functions used to instantiate the FTapplication model: ft_init_appli(), ft_set_appli_mode(), ft_set_appli_control().Actually calls to these functions are automatically generated by the FT-Buildertool into a specific file devoted to init application configuration data structures. So

Figure 1.4 : FT Degraded Mode Management Configuration step3 - EDF + DLM scheduler

Page 183: WP10 -D10.8 Programmer's Guide - MNIS

these last functions may be considered as transparent to the applicationdeveloper.

The ftappmon component has also an internal API for interactions with theftcontroller component for the notification of failed thread.

The ftcontroller has an API for the ftappmon component for the notification ofthe ft-task created and for the switch of ft-task behavior. The ftcontroller has anAPI that could be used by the scheduler mainly to notify events to theftcontroller.

These different intefaces are illustrated in the following figure.

The detailed definition of prototypes necessary at the application level isprovided in files:

${OCERA_DIR/components/ft/ftappmon/include/

ft_api_appmon_appli.h

ft_api_common.h

// FT init appliint ft_init_appli ( int ft_appli_tasks_max_nb, // Number max of appli tasks int ft_appli_modes_max_nb, // Number max of appli modes FT_Appli_Mode ft_cur_appli_mode // Current appli mode );

// FT set_appli_controlextern int ft_set_appli_control ( char *ft_appli_mode_name, FT_Event_Task_Appli_Mode_Elt *ft_evt_task_app_modes_tab );

Page 184: WP10 -D10.8 Programmer's Guide - MNIS

// FT set appli modeextern int ft_set_appli_mode ( char *ft_appli_mode_name, FT_Task_Behavior_Elt *ft_task_behaviors_tab );

// FT task initextern int ft_task_init ( char *ft_task_name, void (*ft_normal_routine)(void*), void (*ft_degraded_routine)(void*), int ft_normal_param, int ft_degraded_param, FT_sched_param ft_normal_sched_param, FT_sched_param ft_degraded_sched_param#ifdef FT_PREALLOCATED_THREAD_STACK /* fxr: stack address and size */ , void *ft_normal_stackaddr, int ft_normal_stacksize, void *ft_degraded_stackaddr, int ft_degraded_stacksize#endif );

// FT task createextern int ft_task_create ( int ft_task_id, FT_task_behavior ft_task_behavior);

// FT task endextern int ft_task_end ( int ft_task_id );

Page 185: WP10 -D10.8 Programmer's Guide - MNIS

/******************************************************************************//* *//* FT API Controller : Other Functions *//* *//******************************************************************************/extern int ft_appli_monitor_stop(void);extern int ft_controller_stop(void);

Important types and structures

FT_task_behavior

// FT-Task behaviortypedef enum { FT_TASK_BEHAVIOR_NOT_DEFINED, // FT-task behavior is not defined FT_TASK_NOT_STARTED, // FT_task has a not started behavior : // normal and degraded thread are suspended FT_TASK_NORMAL, // FT_task has a normal behavior : // normal thread is started, degraded thread is suspended FT_TASK_DEGRADED, // FT_task has a degraded behavior : // normal thread is killed, degraded thread is waked up FT_TASK_TERMINATED // FT_task has a terminated behavior : // normal and degraded threads are killed} FT_task_behavior;

FT_sched_param

// FT_sched_param typedef struct { int prio; // priority hrtime_t start_time;// start time (relative) hrtime_t period; // period (relative) // period <= 0 : aperiodic task // period > 0 : periodic task hrtime_t deadline; // deadline (relative) hrtime_t duration; // estimated duration char algo[10]; // scheduling algorithm : either PRIO, EDF, EDF+SRP int hard_soft_deadline; // Hard (=0) or soft (=1) deadline int count_soft_deadline; // Count value for soft deadline} FT_sched_param;

1.4) Example

The following example named ftnormal+kill is a simple example that illustratres thefunctionning of dynamic reconfiguration on detection of Pthread_kill event.

The application consists of two tasks. The example can be found in :

${OCERA_DIR/components/ft/ftcontroller/examples/ftnormal+kill

It is supposed that design has already been done using Ftbuilder and that generatedmodel files have been copied respectively include and src subdirectories. We remind you

Page 186: WP10 -D10.8 Programmer's Guide - MNIS

that using degraded mode management facility implies the adoption of a specific designprocess and is restricted to a particular task model described in the user's guide. So it isgreatly recommended to read the user'sguide FT section first.

Otherwise, the coding style is quite similar to standard RTLinux programming. Allft_tasks are periodic tasks. You have to provide two routines for each one. A routine fornormal_behavior and a routine for degraded_behavior. The description of the globalapplication model is generated by the ft builder and results into two files that must beincluded in your application.

Include application header

*//*****************************************************************************//* *//* Include *//* *//*****************************************************************************/

// FT application include#include "ft_normal_kill.h"

Init module

/*****************************************************************************//* *//* FT Application : init module *//* *//*****************************************************************************/int init_module(void) {

// Indice int ap_i=0; // String char ap_i_str[4]; // Return code int ap_cr=0;

// Scheduling parameters of normal and degraded threads FT_sched_param ap_normal_sched_param, ap_degraded_sched_param; // Behavior of appli task FT_task_behavior ap_task_behavior;

rtl_printf("\n****************\n"); rtl_printf(" FT_Normal+Kill \n"); rtl_printf("****************\n");

Include model issued by Ftbuilder

/*---------------------------------------------------------------------------*//* *//* FT Application : Appli Modele Source Generated Code *//* *//*---------------------------------------------------------------------------*/

// FT application modele source code (generated code by FT-Builder)

Page 187: WP10 -D10.8 Programmer's Guide - MNIS

#include "ft_appli_model.c"

Init and creation of ft_tasks

/*---------------------------------------------------------------------------*//* *//* FT Application : Init and create FT-tasks *//* *//*---------------------------------------------------------------------------*/

Initialization of scheduling parameters

// Set scheduling parameters of the normal thread ap_normal_sched_param.prio=APPLI_PRIORITY; ap_normal_sched_param.period=APPLI_PERIODE; ap_normal_sched_param.start_time=APPLI_START_TIME; ap_normal_sched_param.deadline=APPLI_DEADLINE; ap_normal_sched_param.duration=APPLI_DURATION;

// Set scheduling parameters of the degraded thread ap_degraded_sched_param.prio=APPLI_PRIORITY; ap_degraded_sched_param.period=APPLI_PERIODE; ap_degraded_sched_param.start_time=APPLI_START_TIME; ap_degraded_sched_param.deadline=APPLI_DEADLINE; ap_degraded_sched_param.duration=APPLI_DURATION;

Loop of init for all ft_tasks

// Loop of init of FT-tasks for (ap_i=1; ap_i < APPLI_TASKS_MAX_NB+1; ap_i++) { /*rtl_printf("\nApplication : ap_i=%d", ap_i);*/

strcpy(&ap_task_name_tab[ap_i][0],"FT_TASK_"); sprintf(ap_i_str, "%d", ap_i); strcat(&ap_task_name_tab[ap_i][0], ap_i_str);

// Init a FT-task // A task has 2 threads with normal and degraded behavior /*rtl_printf("\nApplication : Function init_module : ft_task_init\n");*/ if ((ap_cr=ft_task_init(&ap_task_name_tab[ap_i][0],

(void *)ap_normal_behavior_routine,

(void *)ap_degraded_behavior_routine, ap_i, ap_i, ap_normal_sched_param, ap_degraded_sched_param#ifdef FT_PREALLOCATED_THREAD_STACK

/* fxr: stack address and size */ , NULL, 0, NULL, 0#endif )) < 0) {

Page 188: WP10 -D10.8 Programmer's Guide - MNIS

rtl_printf("\nApplication : ERROR"); rtl_printf("\nApplication : Function init_module"); rtl_printf("\nApplication : Not valid ft_task_init return value"); rtl_printf("\nApplication : ap_i=%d ap_cr=%d\n", ap_i, ap_cr); // Be careful : Necessary output of init_module with error !!! // because it is not possible to start the application // if one of the tasks initialisation has failed return -1; } else { ap_task_id_tab[ap_i]=ap_cr; } }

If init is OK, then the tasks are added to ap_task_id_tab and the actual creationof ft_tasks can be started.

Loop of creation of ft_tasks.

Two tasks are created with default behavior FT_TASK_NORMAL.

Each ft_task creation results in the creation of two threads corresponding to thenormal and degraded beahavior of the ft_task. The ft_task is created with adefault behavior which is generally FT_TASK_NORMAL. The threadcorresponding to normal behavior is then made periodic and started while theother one is suspended.

// Loop of creation of FT-tasks (inverse order : why not) for (ap_i=APPLI_TASKS_MAX_NB; ap_i > 0; ap_i--) { /*rtl_printf("\nApplication : ap_task_id_tab[%d]=%d\n", ap_i, ap_task_id_tab[ap_i]);*/

// Create a FT-task // Create and start the normal thread (awake each FT_APPLI_PERIODE) // Create, start and make wait the degraded thread if (ap_i == 1) { ap_task_behavior=FT_TASK_NORMAL; rtl_printf("\nApplication : ap_i=%d ap_task_behavior=%s\n", ap_i, ft_task_behavior_str[ap_task_behavior]); } else if (ap_i == 2) { ap_task_behavior=FT_TASK_NORMAL; rtl_printf("\nApplication : ap_i=%d ap_task_behavior=%s\n", ap_i, ft_task_behavior_str[ap_task_behavior]); } else { rtl_printf("\nApplication : ERROR"); rtl_printf("\nApplication : Function init_module"); rtl_printf("\nApplication : Not valid appli tasks number"); rtl_printf("\nApplication : ap_i=%d\n", ap_i); return -1; } /*rtl_printf("\nApplication : ", ft_task_behavior_str[ap_task_behavior]);*/ if ((ap_cr=ft_task_create(ap_task_id_tab[ap_i],

ap_task_behavior)) < 0) { rtl_printf("\nApplication : ERROR");

Page 189: WP10 -D10.8 Programmer's Guide - MNIS

rtl_printf("\nApplication : Function init_module"); rtl_printf("\nApplication : Not valid ft_task_create return value"); rtl_printf("\nApplication : ap_task_id_tab[%d]=%d ap_cr=%d\n",

ap_i, ap_task_id_tab[ap_i], ap_cr); // Be careful : Necessary output of init_module with error !!! // because it is not possible to start the application // if one of the tasks creation has failed return -1; } } /*rtl_printf("\nApplication : End of application !!!");*/ return 0;}

Cleanup module

/*****************************************************************************//* *//* FT Application : cleanup module *//* *//*****************************************************************************/void cleanup_module(void) { // Indice int ap_i=0; // Return code int ap_cr=0; rtl_printf("\nApplication : CLEANUP application threads !!!\n"); // Delete all the application FT-tasks for (ap_i=1; ap_i < APPLI_TASKS_MAX_NB+1; ap_i++) { if ((ap_cr=ft_task_end(ap_task_id_tab[ap_i])) < 0) { rtl_printf("\nApplication : ERROR"); rtl_printf("\nApplication : Function cleanup_module"); rtl_printf("\nApplication : Not valid ft_task_end return value"); rtl_printf("\nApplication : ap_task_id_tab[%d]=%d ap_cr=%d", ap_i, ap_task_id_tab[ap_i],ap_cr); // Be careful : NOT necessary output of cleanup_module with error !!! // because it is recommended to stop all the tasks of the application // even if one of the tasks end has failed } } // Stop the FT controller /*ft_controller_stop();*/ // Stop the FT appli monitor /*ft_appli_monitor_stop();*/}MODULE_LICENSE("GPL");

Normal behavior routine definition

In this example, the routine runs 20 cycles then kills itself so that it simulates anerror . The event will then be detected by the controller and the replacementbehavior will be activated.

/*****************************************************************************//* *//* FT Application task : normal behavior routine *//* */

Page 190: WP10 -D10.8 Programmer's Guide - MNIS

/*****************************************************************************/

void *ap_normal_behavior_routine(void *arg) {

int ap_no_cycle=0; int ap_j=0; int ap_nloops=0; int ap_task_id=0; /*int ap_cr=0;*/

ap_task_id = (int) arg;

rtl_printf("\nApplication : ft-task %d, thread %x started, normal behavior", ap_task_id,pthread_self()); rtl_printf("\nApplication : ft-task %d, thread %x switching to wait, normal behavior\n",ap_task_id, pthread_self());

// Infinite loop for appli while(1) { // Wait make periodic or next period of the normal behavior thread !!! pthread_wait_np(); if (ap_no_cycle == 0) rtl_printf("\nApplication : ft-task %d, thread %x switching to running, normal behavior\n",ap_task_id, pthread_self()); ap_no_cycle++; /*rtl_printf("\n\nApplication : ap_task_id=%d ap_task_behavior=NORMAL ap_thread_kid=%xap_no_cycle=%d\n", ap_task_id, pthread_self(), ap_no_cycle);*/

// Start simulation of cancelling the normal behavior thread if ((ap_no_cycle == 20) && (ap_task_id == 2)) { rtl_printf("\nApplication : ft-task %d, thread %x cancelling, normal behavior, no_cycle %d\n",ap_task_id, pthread_self(), ap_no_cycle); pthread_cancel(pthread_self()); break; } // End simulation of cancelling the normal behavior thread

// For test if (ap_no_cycle == 10) { rtl_printf("\nApplication : ft-task %d, thread %x, no_cycle %d, normal behavior\n", ap_task_id, pthread_self(), ap_no_cycle); } // Timing loop ap_nloops=10000; for (ap_j=0; ap_j<ap_nloops; ap_j++);

} // end of 'while'

return (void *)0;}

Degraded behavior routine

Page 191: WP10 -D10.8 Programmer's Guide - MNIS

The degraded behavior routine has the same structure as the normal one.

/*****************************************************************************//* *//* FT Application task : degraded behavior routine *//* *//*****************************************************************************/

void *ap_degraded_behavior_routine(void *arg) {

int ap_no_cycle=0; int ap_j=0; int ap_nloops=0; int ap_task_id=0; /*int ap_cr=0;*/

ap_task_id = (int) arg;

/*** rtl_printf("\nApplication : ft-task %d, thread %x started, degraded behavior",

ap_task_id, pthread_self()); rtl_printf("\nApplication : ft-task %d, thread %x switching to wait, degraded behavior\n",

ap_task_id, pthread_self()); ***/

// Infinite loop for appli while(1) { // Wait make periodic or next period of the degraded behavior thread !!! pthread_wait_np();

if (ap_no_cycle == 0) rtl_printf("\nApplication : ft-task %d, thread %x switching to running, degraded behavior\n",ap_task_id, pthread_self());

ap_no_cycle++;

// For test if (ap_no_cycle == 10) { rtl_printf("\nApplication : ft-task %d, thread %x, no_cycle %d, degraded behavior\n",

ap_task_id, pthread_self(), ap_no_cycle); }

// Timing loop ap_nloops=10000; for (ap_j=0; ap_j<ap_nloops; ap_j++);

} // end of 'while'

return (void *)0;}

a) Application compiling

In order to compile an ft application, it is necessary to have OCERA architectureinstalled and compiled (see general OCERA installation) with the followingcomponents selected :

Page 192: WP10 -D10.8 Programmer's Guide - MNIS

• posixtrace

• ft_components : ftappmon and ft_controller

The application code given as an example is located in the following directory :$OCERA_DIR/components/ft/ftcontroller/examples/ftnormal+kill

The compilation of the example follows a classic module compilation procedure.

- Change to example directory

$ cd $OCERA_DIR/components/ft/ftcontroller/examples/ftnormal+kill

- Clean the$OCERA_DIR/components/ft/ftcontroller/examples/ftnormal+killdirectory:

$ make clean

Old ftnormal+kill.o file is cleaned up if it exists.

- Compile the ftnormal+kill module:

$ make all

The ftnormal+kill.o module is now available under the followingdirectory :

$OCERA_DIR/components/ft/ftcontroller/examples/ftnormal+kill/src

b) Running an application

The procedure to launch the example is the following :

- Go to the ft/ftcontroller/examples/<example_name> directory level :

$ cd $OCERA_DIR/comp/ft/ftcontroller/examples/ftnormal+kill

– Be a root user

$ suPassword:#

At this stage, it is necessary to be a root user. Further, the user has to be anormal user.

– Install and execute all the module:

# make example

- Get the modules execution traces:

# tail -f /var/log/messages

Be careful to see only the last execution traces (not the previousones).

Page 193: WP10 -D10.8 Programmer's Guide - MNIS

c) Additional information and recommendations

prerequisites

FT facilities for degraded mode management of real_time embeddedapplications are available for Hard RTLinux environments only.

All application tasks are RTLinux tasks created within one single applicationmodule that can be dynamically loaded into the system. A user application mustthus consist in one single RTLinux module. As usual this module must containdeclarations, one init_module function and one cleanup_module function.

The prerequisites are thus a running OCERA RTLinux kernel with PosixTraceand FT_components installed (see FT configuration section in chapter three).More precisely, the prerequisites are :

Configuration requirements

-> OS Type

+ Hard and Soft realtime (RTLinux + Linux)

-> Fault Tolerance components

+ FT dependencies + Bigphysarea support

+ Hard Realtime + Degraded Management

+ FT Controller

+ FT Application Monitoring

+ Utilities + Fault Tolerant Building Tool

-> Scheduling

+ Application defined scheduler

+ or EDF

+ or EDF + Deadline miss detection (very experimental)

Scheduling of tasks versus event detection is chosen at the configurationlevel :

- either priority (PRIO) by Application defined scheduler or EDF for onlyPthread_kill events detection,

- or EDF and Deadline_miss detection for Pthread_kill and Deadline_missevents detection.

It is important to consider that the scheduling choice versus event detectionhas to be consistent with application modes transitions in the applicationmodel specification in FT_builder. Remember that the schedulingconfiguration choice automatically configures the FT components atcompilation level for Pthread_kill and/or deadline-miss events detection onthreads by ftcontroller.

Page 194: WP10 -D10.8 Programmer's Guide - MNIS

-> Posix API

+ Posix Trace support

In the example presented in the previous section, only pthread_kills errors weretargetted. If you want to detect also deadline-miss errors you should first makesure that the EDF+DLM configuration options have been selected in theconfiguration steps.

Specify FT parameters of application with FTbuilder

Do not forget that application design must be done using Ftbuilder. Thisacquisition tool is necessary to specify application modes, ft_tasks parametersand application modes transition conditions. It then generates application modelfiles that have to be included in your application.

FT_tasks real-time parameters

The ft_tasks real-time parameters (period, start_time, estimated_duration,deadline, priority) are entered via the FT_builder (see FT task specification inuser'sguide :chapter eight). Static scheduling plan on ft-tasks has to befaisable.

Restrictions and recommandations for these real-time parameters are :

• 1 ms <= period < =100 s

• 0 <= start_time < period

• 0 < estimated_duration < period

• 1 ms <= deadline <= period

• 0 <= priority <=10

Note that the FT components ftappmon and ftcontroller have a priority valuesuperior to the ft_tasks priority values.

Include files

The application header must include the following ft specific files:

• header of the ft_components API : ft_api_appmon_appli.h

• header file for the application model (generated by the FT_builder): ft_appli_model.h

The application source file must include the following ftbuilder generatedspecific file:

• ft_appli_model.c

This file contains the FT application model source code that instanciates internaldata structures of FT components and is used to monitor application andimplement dynamic reconfiguration.

Page 195: WP10 -D10.8 Programmer's Guide - MNIS

2) Redundancy Management

2.1) Description

The Redundancy Management facilities offered by OCERA consist of twocomplementary components: ftredundancymgr and ftreplicamgr. Usedtogether, they provide a framework for implementing redundancy managementsupport for user's application. They respectively control redundancy at theapplication level and at the task level on each node.

This first implementation is intended to provide a basic framework whose goal isto offer a global set of facilities that permit transparent implementation ofredundancy for developers of real-time applications. It offers a passivereplication model, the task model is a simplified one (periodic tasks), fault-detection is based on heartbeats and timeouts, consistency of replicas isensured by periodic checkpointing.

The current implementation is located at Linux user-space level using ORTEcomponent for communication between nodes. However implementation choiceshave been made in such a way as to facilitate the port to OCERA Hard Real-Time level when ORTE become available at this level. Indeed these facilities canbe enriched in the future.

In order to support data consistency and to facilitate tasks recovering on nodecrash, a task model must verify synchronization properties. In the currentimplementation, we have introduced a specific task model described in the FTredundancy management section of the User's guide.

An application consists of a set of ftr_tasks (fault_tolerant redundant tasks). Theyare basically encapsulation of real-time periodic tasks. Creating a ftr_task resultsin the creation oone master (active) thread and several passive replicas(suspended threads). A context object is defined for each ftr_task, theapplication developer must define the set of variables which must be part of thecontext at design time. This context object is automatically updated andbroadcasted at each end of cycle to all passive replicas.

Implementation principles are driven by the will to make redundancymanagement as transparent as possible to the application developer. So inorder to develop an application, the user can almost forget about underlying ftredundancy management architecture.

Page 196: WP10 -D10.8 Programmer's Guide - MNIS

To support the approach, two features are introduced and used within the user'sprocess :

• creation of a control thread dedicated to redundancy control(ftr_control_thread)

• encapsulation of application tasks into ftr_tasks_threads

The ftr_control_thread is in charge of initialization and control of application.Created within the user application process it communicates withftredundancymgr and ftreplicamgr.

The ftr_tasks_threads are generic encapsulation of redundant tasks. Aftr_task_thread is created for each user's application redundant task. It ensuresperiodic execution of user's task routine, management of context entity and ofshared data entities and communication with ftreplicamgr for checkpointing.

Communication with ftreplicamgr and ftredundancymgr are achieved usingORTE publisher/subscriber mechanisms both within a node and between nodes,but this is transparent to the user since calls are made either fromftr_control_thread or from ftr_tasks_threads generic part using specific internalAPIs that are described in the corresponding component sections below.

2.2) Usage

he FT facilities available at soft real-time level are RedundancyManagement.Redundancy Management configuration process takes three steps:

1. OS Type Selection : Soft real-time must be chosen.

2. Components Selection :

• FT components/Soft Realtime/Redundancy Management.

• Communication components/ORTE

1. OS Type Selection

Redundancy Management is provided only at soft real-time level . So the Softreal-time must be selected in the OS type section.

2.1 FT components selection

Select the Soft Realtime subsection in Fault Tolerance components, then the twocomponents Task Replica Manager and Task Redundancy Manager areautomatically selected.

Page 197: WP10 -D10.8 Programmer's Guide - MNIS

2.2ORTE communication component selection

The Redundancy Management facility relies on ORTE (Realtime Ethernet)components that implement RTPS (RealTime Publisher Subscriber Protocol)communication protocol.

So you must select the following features in the communication componentssection.

Figure 2.1 : FT Redundancy Management Configuration step1

Page 198: WP10 -D10.8 Programmer's Guide - MNIS

2.3) Programming Interface (API)

The approach chosen results in a very limited user's API necessary mainly forinitialization and termination of user application. Most of user' s application codeconsists in routines that will be run within ftr_tasks_threads. The important issue isto specify the context data and shared resources for each task at design. Concurrency controlover such shared data is then automatically insured by the execution model. Then threadsroutine can be written simply in a usual way.

So the external user API is actually restricted to the followin few functions :

int ftr_application_register(char *, FTR_APPLI_DESC * , ManagedApp *);int ftr_appli_desc_init(FTR_APPLI_DESC *);int ftr_appli_task_create(FTR_APPLI_TASK_DESC *);int ftr_appli_task_end(int );int ftr_application_terminate(char*);

FT redundancy management User API

They are called within user's main application thread and handled by theftr_control_thread (named hereafter ftr_controller) running within the applicationprocess. Then the ftr_controller uses internal API to communicate withftredundancymgr and with ftreplicamgr.

The ftredundancymgr has a small external API that is used to start or end theredundancy management facility.

In addition, each component has also internal API(s) that permit interactionsbetween them.

Figure 2.2 : FT Redundancy Management Configuration step2

Page 199: WP10 -D10.8 Programmer's Guide - MNIS

a) Principles of application execution

In the following figure we illustrate on a very simple example how an applicationis started.

Once the design is done, the resulting architecture on a node is composed of theuser's process and of the Redundancy Management Facility process (in thefollowing view we do not show ORTE process).

Within the user's process the yellow (or white) parts concern code written byusers and blue (or gray) part concern generic ftr code.

Figure 2.3 : FT Redundancy Management User's API

Redundancy ManagementApplication

ftredundancymgr

ftreplicamgr

ftr_controller

ftr_notify_appli_task_created()ftr_notify_appli_task_cycle_started()ftr_notify_appli_task_cycle_finished()ftr_notify_appli_task_ended()

ftr_task_context_commit()ftr_task_context_update()ftr_shared_data_commit()ftr_shared_data_update()

ftr_application_register ()ftr_appli_desc_init()ftr_appli_task_create()ftr_appli_task_end()ftr_application_terminate()

ftr_notify_task_failed()

ftr_redundancy_management_start()ftr_redundancy_management_end()

ftr_application_config_init()ftr_application_config_modify()

ftr_notify_node_failed()ftr_application_config_checkpoint()ftr_ftredundancymgr_heartbeat()

User Application Main

ftr_task_group_add_member()ftr_task_group_remove_member()ftr_task_group_modify_member_attributes()

ftr_task_checkpoint()ftr_ftreplicamgr_heartbeat()

ftr_task_group_init()ftr_task_group_destroy()

Page 200: WP10 -D10.8 Programmer's Guide - MNIS

First the application creates the ftr_control_thread (1), then it calls theftr_application_register primitive to register the application (2), theftr_control_thread then communicates with the ftredundancymgr to setup data(3) for the new application, and waits for acknowledgment (4) from it beforereturning OK (5) to the user main thread.

Then the ftr_appli_desc_init primitive is called to setup application datastructures and ftr_tasks_threads (6). At this stage ftr_tasks_threads are createdbut the corresponding users routines are not started. When all the infrastructureis ready, the ftreplicamgr notifies the ftr_control_thread (7) which returns OK (8)to user's main thread.

Finally the user can call the ftr_appli_task_create primitive to start a ftr_task.(9).The ftr_controller_thread then makes the ftr_task_thread start periodic call to the correspondinguser's ftr_task_routine (10).

Two other primitives are available to end an ftr_appli_task ( ftr_appli_task_end) and toterminate the overall application( ftr_application_terminate ).

The user has to define specific data structures, one to describe the overallapplication structure and one to describe each ftr_task.

It is intended that the Ftbuilder tool (already available for the specification of degraded modemanagement) will assist the designer to determine these features and automatically generate thecorresponding data structures. For the moment this facility is not implemented yet, and data isprovided in a file read by the ftr_appli_desc_init primitive.

Figure 2.4 : FT Redundancy Management - application executionprinciples

Node1

FTR Application : node1

ftr_task

T1:m

Redundancy Management Faclity

CT1

ftredundancymgr ftreplicamgr

main ftr_control

r1m

Replica management

1

2

3

5

4

68

7

910

Global Application & Network control

Page 201: WP10 -D10.8 Programmer's Guide - MNIS

2.4) Example

It is intended that the Ftbuilder tool (already available for the specification ofdegraded mode management) will assist the designer to determine thesefeatures and automatically generate the corresponding data structures. For themoment this facility is not implemented yet, and data is provided in a file read bythe ftr_appli_desc_init primitive.

a) Coding steps

An application can be written rather simply following the different generic steps :

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <orte.h>#include <netdb.h>#include <pthread.h>#include <simple_appli.h>#include <ftredundancymgr.h>#include <appli_controller.h>ManagedApp *appli;pthread_t ftr_control_thread;int main(void){ int res = 0; void *ret; FTR_APPLI_DESC application_desc; FTR_APPLI_TASK_DESC application_task_desc_1; FTR_APPLI_TASK_DESC application_task_desc_2;

1. Declarations for ftr_application

/* Creation of ftr_control_thread */ pthread_create(&ftr_control_thread, NULL,(*ftr_main_control_routine), NULL); if (res != 0) { perror("Redundancy Management thread creation failure ... exiting"); exit(-1); };

2. Creation of ftr_control_thread of ftr_application

The ftr_control_thread of the application is created in the beginning of the mainthread to install the ftr architecture within the application process. In the future, itwill be replaced by a macro. The ftr_main_control_routine, is a generic controlloop that monitors events from and to the ftr_process. It also accepts requestsform the user main thread.

/* Init appli_desc structure */ res = ftr_appli_desc_init(&application_desc);

Page 202: WP10 -D10.8 Programmer's Guide - MNIS

if (res == -1) {perror("Redundancy Management : application desc init failed ...

exiting"); exit(-1); };

3. initialization of application data structures

During this step, data structures describing application and tasks are initialized.

/* Register application */ res = ftr_application_register(APPLI_NAME, &application_desc,appli); if (res == -1) { perror("Redundancy Management : application registration failed... exiting"); exit(-1); };

4. Registration of application

Application registration is done towards ftr process which in turn propagateinformation over network (thanks to ORTE) to other ftr processes. (Application isalso registered as ORTE Application). (Internal tables are initialized, groups ofreplicas are created and instances created on each node).

/* Tasks creation */ application_task_desc_1 = application_desc.appli_tasks_tab[1]; application_task_desc_1.appli_task_routine = ft1; res = ftr_appli_task_create(&application_task_desc_1);if (res == -1) { perror("Redundancy Management : task creation (1) failed... exiting"); exit(-1); };...

5. ftr_tasks creation for ftr_application

During this step each application task is created using the ftr_task_desc of eachone. This steps defines mainly the routine to be run within the genericftr_task_thread and the related real-time parameters (period,estimated_duration, deadline). At the end of each period, the current context issent to all its replicas on other nodes.

Once this is done for each task, the application runs in a nominal way.

To end a task the following call is necessary.

/* Requiring End of Task 1 */ res = ftr_appli_task_end(1);...

6. ftr_tasks ending for ftr_application

This ends the corresponding ftr_task (and all its replicas). All ftr_tasks have to beended before application itself can be ended.

/* Requiring Application Termination */ ftr_application_terminate(APPLI_NAME); /* Waiting for end of control_thread */

Page 203: WP10 -D10.8 Programmer's Guide - MNIS

pthread_join(ftr_control_thread,&ret); if (ret != PTHREAD_CANCELED) { i = (int) ret; printf("Main : end of ftr_control_thread ret = %d\n", i); };

printf("\nAppli ending : "); return 0;}

7. Termination of ftr_application

Once all the ftr_tasks are ended, resources are freed and the ftr_control_threadis ended, then application terminates.

Obviously, the user must in addition provide the code of the routines that will berun within each ftr_tasks_thread. A pointer to this routine is a member of theftr_task_desc structure.

In our simple example :

int ft1(int i){ printf("Function ft1 running with arg %d\n",i); sleep(3); return 0;}

The status of the current implementation is still in a testing phase. The exampleimplemented tests application setup, execution and termination.

b) How to run the examples

Up to now, the examples developed are common to the two components.Theexample directory is located within the ftredundancymgr component :

ocera/components/ft/ftredundancymgr/examples/ftr_appli

It is the Makefile located within this directory that builds the test application. Inorder to run the example it is necessary to compile and start the ftredundancymanagement facility first.

Implementation :

The ft/ftredundancymgr/examples/ directory has the following structure:

examples ! --- README ! --- INSTALL ! --- Makefile ! --- ftr_appli ! !--- README ! !--- INSTALL ! !--- Makefile ! !--- include ! ! !---ftr_appli.h ! !--- src ! ! !---ftr_appli.c

Page 204: WP10 -D10.8 Programmer's Guide - MNIS

The ftr_appli is a simple application that has been developed to test theftredundancy management facility.

The general OCERA Makefile file permits the compilation of the overall OCERAtree provided options are selected in the configuration step (see OCERAHOWTO for OCERA configuration steps). However examples can be compiledseparately afterwards.

Compilation :

In order to compile the example please follow next steps :

- Go to the ft/ftredundancymngr/examples directory:$ cd ft/ftredundancymngr/examples

- Clean the ft/ftredundancymngr/examples directory:$ make clean

- Compile the examples:$ make

Installation/Execution :

Note that execution of examples requires a distributed architecture. So theftcomponents and examples must be present on each machine that will beinvolved in the test. This requires additional operations and controls before theexample can be run.

• Install OCERA (or at least ORTE and ftcomponents) on each machine.

• Insure that rights are set so as to allow for remote execution of the codecorresponding to both components and application.

• Set up environment variables

(See section 2.7 for details)

The example runs on two nodes N1 and N2. The application has two tasks T1and T2.

T1 master task is running on node N1 and T2 master task is running on Node2.Node1 is the master node on application start.

To run the application one must :

• start ftredundancy management

A shell script allows for this, it is located in ft/ftredundancymngr/src:

$ ftrm_start <Node1> <Node2> where <Nodei> is an hostname

It starts ORTEManager on each node, then starts ftredundancycomponents on each node. Actually the two components of a nodeare linked a single Linux executable named ft_redman.

Page 205: WP10 -D10.8 Programmer's Guide - MNIS

The master node is the current node (it must be the same as thefirst argument , here Node1).

• start application on master node

$ cd ftr_appli/src

$ ./ftr_appli

The application starts first on Node1 then on Node2. Replicas arecreated and ftr_tasks started.

After a given number of cycles the application ends.

c) Comments

The current implementation is still a prototype one and the development status isvery experimental.We have adopted an incremental development cycle andsome functionalities have still very basic implementation. The main goal of thisstep was to provide a consistent overall framework for redundancy management.A lot of work has still to be done to make an efficient operational environment ofit.

However, the example has permitted to test the ft redundancy managementoverall structure .

• Ft redundancy framework set-up and functioning

• Application registration

• Application execution

• Application termination.

• Node crash detection

• Application dynamic reconfiguration.

Page 206: WP10 -D10.8 Programmer's Guide - MNIS

X) CAN

ByFrantisek Vacek - CTUPavel Pisa - CTU

1) Installation

CAN commponet uses the OMK make system. There is no ./configure script.The component can be built as a part of OCERA tree or as a stanalone. If it isbuild as a standalone you should run script can/switch2standalone.

[fanda@lab3-2 can]$ ./switch2standaloneDefault config for /utils/suiutDefault config for /utils/ulutDefault config for /utils/flibDefault config for /utilsDefault config for /canvca/libvcaDefault config for /canvca/cantestDefault config for /canvcaDefault config for /candev/cpickleDefault config for /candev/nascanhwDefault config for /candevDefault config for /canmon/canmondDefault config for /canmon/canmonitorDefault config for /canmonDefault config for /lincan/srcDefault config for /lincan/utilsDefault config for /lincanDefault config for

To modify required configuration options, create "config.omk" fileand add modified lines from "config.omk-default" file into it

Page 207: WP10 -D10.8 Programmer's Guide - MNIS

To build project, call simple "make"

GNU make program version 3.81beta1 or newer is required to build projectcheck by "make --version" command

Default configuration of any subcommponent can be changed by introducing afile config.omk in the subcommponent directory. Defines in this file simplybeats defines in file config.omk-default, so you can put there only definesthat are different that the default ones in the config.omk-default.

For example by default the building of Java application is disabled. That meansthat there is a line CONFIG_OC_CANMONITOR=n in the config.omk-default. If you have the Java SDK and the ant build system installed, add theline CONFIG_OC_CANMONITOR=y to the file config.omk to enable the Javaapplications to be build.

When you switch to standalone, you can build any particular commponent byrunning make in the commponent directory.

For more details see file can/README.makerules.

You can download make version 3.81beta1 source fromhttp://cmp.felk.cvut.cz/~pisa/can/make-3.81beta1.tar.gz or the binary fromhttp://cmp.felk.cvut.cz/~pisa/can/make-3.81beta1-i586-0.gz.

Programs in this package does not need special installation. They can run fromany directory. Just type make in can/canmon directory and copy desired fileswherever you want. The make process is an out source build. After make youcan find your binaries in directory can/_compiled/bin. If you want to compileonly one component, type make in the component's directory. That commponentand all commponents in subdirectories will be build.

Restrictions on versions of GNU C or glibc are not known in this stage of projectbut gcc ver >= 3.0 is recommended. Java SDK ver. 1.4 or above is alsorecommended (assert keyword support).

Page 208: WP10 -D10.8 Programmer's Guide - MNIS

2) API / Compatibility

2.1) VCA base API

Name

struct canmsg_t — structure representing CAN message

Synopsisstruct canmsg_t { int flags; int cob; unsigned long id; canmsg_tstamp_t timestamp; unsigned short length; unsigned char * data;};

Members

flagsmessage flags MSG_RTR .. message is Remote Transmission Request,MSG_EXT .. message with extended ID, MSG_OVR .. indication of queueoverflow condition, MSG_LOCAL .. message originates from this node.

cobcommunication object number (not used)

idID of CAN message

timestampnot used

lengthlength of used data

data

Page 209: WP10 -D10.8 Programmer's Guide - MNIS

data bytes buffer

Header

canmsg.h

Name

struct canfilt_t — structure for acceptance filter setup

Synopsisstruct canfilt_t { int flags; int queid; int cob; unsigned long id; unsigned long mask;};

Members

flagsmessage flags MSG_RTR .. message is Remote Transmission Request,MSG_EXT .. message with extended ID, MSG_OVR .. indication of queueoverflow condition, MSG_LOCAL .. message originates from this node. thereare corresponding mask bits MSG_RTR_MASK, MSG_EXT_MASK,MSG_LOCAL_MASK. MSG_PROCESSLOCAL enables local messagesprocessing in the combination with global setting

queidCAN queue identification in the case of the multiple queues per one user(open instance)

cobcommunication object number (not used)

idselected required value of cared ID id bits

maskselect bits significand for the comparation; 1 .. take care aboutcorresponding ID bit, 0 .. don't care

Header

canmsg.h

Name

vca_h5log — converts VCA handle to printable number

Page 210: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis

long vca_h5log (vcah);vca_handle_t vcah;

Arguments

vcahVCA handle

Header

can_vca.h

Return Value

unique printable VCA handle number

Name

vca_open_handle — opens new VCA handle from CAN driver

Synopsisint vca_open_handle (vcah_p, dev_name, options, flags); vca_handle_t *

vcah_p;

const char * dev_name;

const char * options;int flags;

Arguments

vcah_ppoints to location filled by new VCA handle

dev_namename of requested CAN device, if NULL, default VCA_DEV_NAME is used

optionsoptions argument, can be NULL

flagsflags modifying style of open (VCA_O_NOBLOCK)

Header

can_vca.h

Page 211: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

VCA_OK in case of success

Name

vca_close_handle — closes previously acquired VCA handle

Synopsis

int vca_close_handle (vcah);vca_handle_t vcah;

Arguments

vcahVCA handle

Header

can_vca.h

Return Value

Same as libc close returns.

Name

vca_send_msg_seq — sends sequentially block of CAN messages

Synopsisint vca_send_msg_seq (vcah, messages, count); vca_handle_t

vcah;

canmsg_t * messages;int count;

Arguments

vcahVCA handle

messagespoints to continuous array of CAN messages to send

countcount of messages in array

Page 212: WP10 -D10.8 Programmer's Guide - MNIS

Header

can_vca.h

Return Value

Number of sucessfully sent messages or error < 0

Name

vca_rec_msg_seq — receive sequential block of CAN messages

Synopsisint vca_rec_msg_seq (vcah, messages, count); vca_handle_t

vcah;

canmsg_t * messages;int count;

Arguments

vcahVCA handle

messagespoints to array for received CAN messages

countnumber of message slots in array

Header

can_vca.h

Return Value

number of received messages or error < 0

Name

vca_wait — blocking wait for the new message(s)

Synopsisint vca_wait (vcah, wait_msec, what);

Page 213: WP10 -D10.8 Programmer's Guide - MNIS

vca_handle_t

vcah;

int wait_msec;int what;

Arguments

vcahVCA handle

wait_msecnumber of miliseconds to wait, 0 => forever

what0,1 => wait for Rx message, 2 => wait for Tx - free 3 => wait for both

Header

can_vca.h

Return Value

Positive value if wait condition is satisfied

Name

vca_gethex — gets one hexadecimal number from string

Synopsis

int vca_gethex (str, u);const char * str;int * u;

Arguments

strscanned string

upointer to store got value

Return

the number of eaten chars

Header

can_vca.h

Page 214: WP10 -D10.8 Programmer's Guide - MNIS

Name

vca_strmatch — get token from string

Synopsisint vca_strmatch (str, template); const char * str;const char * template;

Arguments

strscanned string

templatetoken template template consists of characters and '~' matching one ormore of spaces ie. '~hello' matches ' hello', ' hello', ' hello' etc.

Return

the number of used chars from str if match or negative value (number of partiallymatched chars from str - 1) if template does not match

Header

can_vca.h

Name

vca_msg2str — converts canmsg_t to the string

Synopsisint vca_msg2str (can_msg, buff, buff_len); const struct canmsg_t *

can_msg;

char * buff;int buff_len;

Arguments

can_msgpointer to the serialized CAN message

buffbuffer for the serialized string

buff_lenmax length of serialized string, including terminating zero

Page 215: WP10 -D10.8 Programmer's Guide - MNIS

Return

the number of written chars not including terminating zero

Header

can_vca.h

Name

vca_byte2str — converts byte to the string

Synopsisconst char* vca_byte2str (b, base); unsigned char b;int base;

Arguments

bbyte to convert

basebase, can be (2, 8, 16)

Return

string representation of b in chosen base

Header

can_vca.h

Name

vca_str2msg — converts the string to the canmsg_t object

Synopsisint vca_str2msg (can_msg, str); struct canmsg_t *

can_msg;

const char * str;

Arguments

can_msgpointer to the serialized CAN message

Page 216: WP10 -D10.8 Programmer's Guide - MNIS

strstring representing CAN message

Return

number of read chars if succeed else zero or negative value.

Header

can_vca.h

Name

vca_cmp_terminated — compares two strings terminated either by '\0' or byterminator.

Synopsisint vca_cmp_terminated (pa, pb, terminator); const char * pa;const char * pb;char terminator;

Arguments

pafirst string

pbsecond string

terminatoraditional char (\0 stil terminates string too), that indicates end of string

Description

Usefull when one works with the path names.

Return

the same value like libc strcmp does.

Header

can_vca.h

Name

vca_log — generic logging facility for VCA library

Page 217: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisvoid vca_log (domain, level, format, ...); const char * domain;int level;const char * format;... ...;

Arguments

domainpointer to character string representing source of logged event, it isVCA_LDOMAIN for library itself

levelseverity level

formatprintf style format followed by arguments

...variable arguments

Description

This functions is used for logging of various events. If not overridden byapplication, logged messages goes to the stderr. Environment variableVCA_LOG_FILENAME can be used to redirect output to file. Environment variableVCA_DEBUG_FLG can be used to select different set of logged events throughvca_debug_flg.

Note

There is a global variable vca_log_cutoff_level. Only the messages withlevel <= vca_log_cutoff_level will be logged. see can_vca.h

Name

vca_log_redir — redirects default log output function

Synopsisvoid vca_log_redir ( log_fnc, add_flags); vca_log_fnc_t *

log_fnc;

int add_flags;

Page 218: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

log_fncnew log output function. Value NULL resets to default function

add_flagssome more flags

2.2) SDO processing API

Name

struct vcasdo_fsm_t — structure representing SDO FSM

Synopsisstruct vcasdo_fsm_t { unsigned srvcli_cob_id; unsigned clisrv_cob_id; unsigned node; unsigned index, subindex; struct timeval last_activity; int bytes_to_load; unsigned char toggle_bit; char is_server; char is_uploader; int state; vcasdo_fsm_state_fnc_t * statefnc; int err_no; ul_dbuff_t data; canmsg_t out_msg;};

Members

srvcli_cob_idSDO server-client COB_ID (default is 0x580 + node), port on which masterlisten

clisrv_cob_idSDO client-server COB_ID (default is 0x600 + node), port on which slavelisten

nodeCANopen node number

subindexsubindex of communicated object

last_activitytime of last FSM activity (internal use)

bytes_to_loadnumber of stil not uploaded SDO data bytes (internal use)

toggle_bit

Page 219: WP10 -D10.8 Programmer's Guide - MNIS

(internal use)is_server

type of FSM client or server (Master or Slave) (internal use)is_uploader

processing upload/download in state sdofsmRun, sdofsmDonestate

state of SDO (sdofsmIdle = 0, sdofsmRun, sdofsmDone,sdofsmError, sdofsmAbort)

statefncpointer to the state function (internal use)

err_noerror number in state sdofsmError.

datauploaded/downloaded bytes (see ul_dbuff.h)

out_msgif vcasdo_taste_msg generates answer, it is stored in the out_msg

Header

vcasdo_fsm.h

Name

vcasdo_fsm_upload1 — starts SDO upload using parameters set by previouscalling vcasdo_init_fsm

Synopsisint vcasdo_fsm_upload1 ( fsm); vcasdo_fsm_t *

fsm;

Arguments

fsmFSM to work with

Return

the same as vcasdo_fsm_upload1

See also

vcasdo_fsm_upload1.

Header

vcasdo_fsm.h

Page 220: WP10 -D10.8 Programmer's Guide - MNIS

Name

vcasdo_fsm_download1 — starts SDO download using parameters set byprevious calling vcasdo_init_fsm

Synopsisint vcasdo_fsm_download1 ( fsm, data); vcasdo_fsm_t *

fsm;

ul_dbuff_t * data;

Arguments

fsmFSM to work with

datapointer to &ul_dbuff_t structure where downloaded data will be stored

Return

the same as vcasdo_fsm_download

See also

vcasdo_fsm_download.

Header

vcasdo_fsm.h

Name

vcasdo_read_multiplexor — reads index and subindex from multiplexor part ofCANopen mesage

Synopsisvoid vcasdo_read_multiplexor (mult, index, subindex); const byte * mult;unsigned * index;unsigned * subindex;

Arguments

multpointer to the multiplexor part of CANopen mesage

Page 221: WP10 -D10.8 Programmer's Guide - MNIS

indexpointer to place to store read index

subindexpointer to place to store read subindex

Header

vcasdo_fsm.h

Name

vcasdo_error_msg — translates err_no to the string message

Synopsis

const char* vcasdo_error_msg (err_no);int err_no;

Arguments

err_nonumber of error, if FSM state == sdofsmError

Return

textual error description.

Header

vcasdo_fsm.h

Name

vcasdo_init_fsm — init SDO FSM

Synopsisvoid vcasdo_init_fsm ( fsm, srvcli_cob_id, clisrv_cob_id, node); vcasdo_fsm_t *

fsm;

unsigned srvcli_cob_id;unsigned clisrv_cob_id;unsigned node;

Page 222: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

fsmfsm to init

srvcli_cob_idport to use for server->client communication (default 0x850 used ifsrvcli_cob_id==0)

clisrv_cob_idport to use for client->server communication (default 0x600 used ifclisrv_cob_id==0)

nodenumber of node on CAN bus to communicate with

Header

vcasdo_fsm.h

Name

vcasdo_destroy_fsm — frees all SDO FSM resources (destructor)

Synopsisvoid vcasdo_destroy_fsm ( fsm); vcasdo_fsm_t *

fsm;

Arguments

fsmfsm to destroy

Header

vcasdo_fsm.h

Name

vcasdo_fsm_idle — sets SDO FSM to idle state

Synopsis

void vcasdo_fsm_idle (fsm);vcasdo_fsm_t * fsm;

Arguments

fsmSDO FSM

Page 223: WP10 -D10.8 Programmer's Guide - MNIS

Header

vcasdo_fsm.h

Name

vcasdo_fsm_run — starts SDO communication protocol for this FSM

Synopsis

void vcasdo_fsm_run (fsm);vcasdo_fsm_t * fsm;

Arguments

fsmSDO FSM

Header

vcasdo_fsm.h

Name

vcasdo_fsm_abort — aborts SDO communication for this FSM, fill abort out_msg

Synopsisvoid vcasdo_fsm_abort ( fsm, abort_code); vcasdo_fsm_t *

fsm;

uint32_t abort_code;

Arguments

fsmSDO FSM

abort_codecode to fill to out_msg

Header

vcasdo_fsm.h

Name

vcasdo_fsm_upload — starts upload SDO communication protocol for this FSM

Page 224: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint vcasdo_fsm_upload ( fsm, node, index, subindex, srvcli_cob_id, clisrv_cob_id); vcasdo_fsm_t *

fsm;

int node;unsigned index;byte subindex;unsigned srvcli_cob_id;unsigned clisrv_cob_id;

Arguments

fsmSDO FSM

nodeCANopen device node to upload from

indexuploaded object index

subindexuploaded object subindex

srvcli_cob_idport to use for server->client communication (default 0x850 used ifsrvcli_cob_id==0)

clisrv_cob_idport to use for client->server communication (default 0x600 used ifclisrv_cob_id==0)

Return

not 0 if fsm->out_msg contains CAN message to sent

Header

vcasdo_fsm.h

Name

vcasdo_fsm_download — starts download SDO communication protocol for thisFSM

Synopsisint vcasdo_fsm_download ( fsm,

Page 225: WP10 -D10.8 Programmer's Guide - MNIS

dbuff, node, index, subindex, srvcli_cob_id, clisrv_cob_id); vcasdo_fsm_t *

fsm;

ul_dbuff_t * dbuff;int node;unsigned index;byte subindex;unsigned srvcli_cob_id;unsigned clisrv_cob_id;

Arguments

fsmSDO FSM

dbuffpointer to a ul_dbuff structure to store received/transmitted data

nodeCANopen device node to upload from

indexuploaded object index

subindexuploaded object subindex

srvcli_cob_idport to use for server->client communication (default 0x850 used ifsrvcli_cob_id==0)

clisrv_cob_idport to use for client->server communication (default 0x600 used ifclisrv_cob_id==0)

Return

not 0 if fsm->out_msg contains CAN message to sent

Header

vcasdo_fsm.h

Name

vcasdo_fsm_taste_msg — try to process msg in FSM

Page 226: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint vcasdo_fsm_taste_msg ( fsm, msg); vcasdo_fsm_t * fsm;const canmsg_t *

msg;

Arguments

fsmfsm to process msg

msgtasted msg

Return

0 if msg is not eatable for FSM, -1 if message has correct CobID but cann't beprocessed in current FSM state, 1 if message is processed,

Header

vcasdo_fsm.h

Name

vcasdo_abort_msg — translates SDO abort_code to the string message

Synopsisconst char* vcasdo_abort_msg (abort_code); uint32_t

abort_code;

Arguments

abort_codeabort code

Header

vcasdo_msg.h

Page 227: WP10 -D10.8 Programmer's Guide - MNIS

2.3) PDO processing API

Name

struct vcapdo_mapping_t — structure representing mapping of sigle object inPDO

Synopsisstruct vcapdo_mapping_t { vcaod_object_t * object; unsigned char start; unsigned char len; sui_dinfo_t * dinfo;};

Members

objectpointer to the mapped object

startbit offset of object value in PDO

lenbit length of object value in PDO

dinfopointer to object data source. Every PDO can be read/written throughdinfo to the OD or to hardware. Actualy there is no other way for PDOobject to do that.

Header

vca_pdo.h

Name

struct vcapdolst_object_t — structure representing single PDO object

Synopsisstruct vcapdolst_object_t { gavl_node_t my_node; struct vcaPDOProcessor_t * pdo_processor; unsigned long cob_id; unsigned char transmition_type; unsigned flags; unsigned char sync_every; unsigned char sync_counter; uint16_t inhibit_time; uint16_t event_timer; unsigned char * pdo_buff; int mapped_cnt;

Page 228: WP10 -D10.8 Programmer's Guide - MNIS

vcapdo_mapping_t * mapped_objects; evc_rx_hub_t rx_hub;};

Members

my_nodestructure necessary for storing node in GAVL tree

pdo_processorpointer to PDO processor servicing this PDO

cob_idCOB ID of PDO

transmition_typetype of PDO transmission according to DS301 table 55

flagsPDO characteristics and parsed transmission_type

sync_everysynchronous PDO will be processed every n-th SYNC message

sync_counterauxiliary variable for sync_every

inhibit_timeminimum gap between two PDO transmissions (multiples of 100 us)

event_timerif nonzero, PDO is transmitted every event_timer ms. Valid only intransmission modes 254, 255. (!vcapdoFlagSynchronous && !vcapdoFlagRTROnly)

pdo_buffbuffer for received/transmitted PDO

mapped_cntnumber of mapped objects in OD

mapped_objectsarray to structures describing mapping details for all mapped objects

rx_hubIf PDO communication is event driven, appropriate events are connected tothis hub

See also

GAVL usage (ul_gavlchk.c)

Header

vca_pdo.h

Name

struct vcapdolst_root_t — structure representing root of OD

Page 229: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisstruct vcapdolst_root_t { gavl_node_t * my_root;};

Members

my_rootobject dictionary GAVL tree root

See also

GAVL usage (ul_gavlchk.c)

Header

vca_pdo.h

Name

struct vcaPDOProcessor_t — structure used for PDO communication

Synopsisstruct vcaPDOProcessor_t { vcapdolst_root_t pdolst_root; // TODO send_to_can_fnc: remove this hack and add queue of outcomingCAN messages// to make this library thread safe.// At presentsend_to_can_fnc should be thread safe.vcapdo_send_to_can_fnc_t *; vcaod_root_t * od_root; //vcaDinfoManager_t * dinfo_mgr; int node_id;};

Members

pdolst_rootGAVL containing all defined &vcapdolst_object_t structures

send_to_can_fncPDOProcessor should use this function if it needs to send CAN messageduring processing

od_rootpointer to used OD (necessary for PDOs creation and initialization invcaPDOProcessor_createPDOLIst)

dinfo_mgrpointer to used DinfoManager (providing HW dinfos during initialization)

node_idNode number, optional parameter, if it is specified, default PDO COB-IDscan be assigned if they are not specified in EDS. If node_id is 0, then it isignored.

Page 230: WP10 -D10.8 Programmer's Guide - MNIS

Description

vcaPDOProcessor is responsible for all PDO related tasks in CANopen device

Header

vca_pdo.h

Name

vcaPDOProcessor_init — vcaPDOProcessor constructor

Synopsisvoid vcaPDOProcessor_init (proc); vcaPDOProcessor_t *

proc;

Arguments

procpointer to PDO processor to work with

Header

vca_pdo.h

Name

vcaPDOProcessor_destroy — vcaPDOProcessor destructor

Synopsisvoid vcaPDOProcessor_destroy (proc); vcaPDOProcessor_t *

proc;

Arguments

procpointer to PDO processor to work with

Description

It releases all PDO objects

Header

vca_pdo.h

Page 231: WP10 -D10.8 Programmer's Guide - MNIS

Name

vcaPDOProcessor_setOD — assign OD to PDOProcessor

Synopsisvoid vcaPDOProcessor_setOD (proc, od_root); vcaPDOProcessor_t *

proc;

vcaod_root_t * od_root;

Arguments

procpointer to PDO processor to work with

od_rootassigned root of Object Dictionary

Header

vca_pdo.h

Name

vcaPDOProcessor_createPDOList — scans OD and creates all valid PDOstructures.

Synopsisint vcaPDOProcessor_createPDOList (proc); vcaPDOProcessor_t *

proc;

Arguments

procpointer to PDO processor to work with

Description

It also deletes previously created PDO structures (if any).

Return

0 or negative number in case of an error

Header

vca_pdo.h

Page 232: WP10 -D10.8 Programmer's Guide - MNIS

Name

_vcaPDOProcessor_disconnectDinfoLinks — disconnect all PDOs and theirdinfo structures

Synopsisvoid _vcaPDOProcessor_disconnectDinfoLinks (proc); vcaPDOProcessor_t *

proc;

Arguments

procpointer to PDO processor to work with

Description

Actualy it only decrements RefCnt, so only dinfos with RefCnt==1 will be deleted

Note

this function is internal and it is not a part of VCA PDO public interface.

Header

vca_pdo.h

Name

vcaPDOProcessor_connectDinfoLinks — scans defined PDOs and makesnecessary data links from PDOs to OD and HW

Synopsisvoid vcaPDOProcessor_connectDinfoLinks (proc); vcaPDOProcessor_t *

proc;

Arguments

procpointer to PDO processor to work with

Description

Disconnect all connected dinfos. For each mapped object tries to findappropriate dinfo asking DinfoManager. If DinfoManager returns NULL, thatsmeans, that no HW is connected to this object. In such case function createsdbuff_dinfo for data stored in OD and connect it to mapped PDO.

Page 233: WP10 -D10.8 Programmer's Guide - MNIS

Header

vca_pdo.h

Name

vcaPDOProcessor_processMsg — tries to process msg

Synopsisint vcaPDOProcessor_processMsg (proc, msg); vcaPDOProcessor_t *

proc;

canmsg_t * msg;

Arguments

procpointer to PDO processor to work with

msgCAN msg to proceed

Return

zero if msg is processed

Header

vca_pdo.h

2.4) OD access API

Name

struct vcaod_root_t — structure representing root of OD

Synopsisstruct vcaod_root_t { gsa_array_field_t my_root;};

Members

my_rootobject dictionary GAVL tree root

Page 234: WP10 -D10.8 Programmer's Guide - MNIS

Header

vca_od.h

Name

struct vcaod_object_t — structure representing single object in OD

Synopsisstruct vcaod_object_t { #ifndef CONFIG_OD_GSAgavl_node_t my_node; #endifunsigned index; int subindex; unsigned char data_type; unsigned object_type; int access; unsigned flags; char * name; struct vcaod_object_t * subobjects; int subcnt; vcaod_dbuff_t value; sui_dinfo_t * dinfo;};

Members

my_nodestructure neccessary for storing node in GAVL tree, is NULL for subindicies

indexindex of object

subindexsubindex of subobject or -1 if object is not subobject

data_typecan be one of (BOOLEAN, INTEGER8, ...)

object_typetype of object (DOMAIN=2, DEFTYPE=5, DEFSTRUCT=6, VAR=7,ARRAY=8, RECORD=9)

accessaccess attributes (RW, WO, RO, CONST)

flagsflags can be: VCAOD_OBJECT_FLAG_MANDATORY object ismandatory/optional, VCAOD_OBJECT_FLAG_PDO_MAPPING object issupposed to be PDO mapped, VCAOD_OBJECT_FLAG_WEAK_DINFOdinfo is weak pointer

nametextual name of object

subobjectspointer to array of subobjects (definition==DEFSTRUCT, RECORD) orNULL

Page 235: WP10 -D10.8 Programmer's Guide - MNIS

subcntnumber of subobjects

valueobject values (definition==ARRAY) or single value (other definitions). Ifdefinition==ARRAY all values have the same length and they are storedsequently in value

dinfoReference to dinfo associated with current object. There are couple ofreasons for such a association. 1. Object is PDO mapped but its valuedoesn't come from HW dinfo (it is not tecnological value) - in such a casedbuff dinfo is created and referenced from that OD object. 2. Object is PDOmapped and its value comes from HW dinfo (it is tecnological value) - insuch a case only weak reference is in OD object. When HW module isunloaded or dinfo will be destroyed from any reason, also weak referenceto it will be cleared to NULL. 3. Object is not PDO mapped but its valuecomes from HW dinfo - in such a case even SDO communication sholudread that dinfo to get the propper object value.

Header

vca_od.h

Name

vcaod_find_object — finds object in OD. This function is not a part of the SDOAPI

Synopsisvcaod_object_t* vcaod_find_object (odroot, ix, subix, abort_code); vcaod_root_t *

odroot;

unsigned ix;unsigned subix;uint32_t * abort_code;

Arguments

odrootobject dictionary

ixobject index

subixobject subindex, ignored if object does not have subobjects

abort_code

Page 236: WP10 -D10.8 Programmer's Guide - MNIS

Pointer to the abort code in case of an ERROR. It can be NULL, than it isignored. Abort codes are defined in CANopen standart 301 and can betranslated to text calling vcasdo_abort_msg.

Return

found object or NULL

Header

vca_od.h

Name

vcaod_get_value — reads object value from Object Dictionary and copies themto caller buffer

Synopsisint vcaod_get_value (object, array_index, buff, len, abort_code); const vcaod_object_t*

object;

int array_index;void * buff;int len;uint32_t * abort_code;

Arguments

objectobject from dictionary, see. vcaod_find_object

array_indexif object is an array array_index specifies which index to get, othervise itis ignored.

buffbuffer to write requested data

lenlength of the buffer

abort_codePointer to the abort code in case of an ERROR. It can be NULL, than it isignored. Abort codes are defined in CANopen standart 301 and can betranslated to text calling vcasdo_abort_msg.

Page 237: WP10 -D10.8 Programmer's Guide - MNIS

Return

number of read bytes negative value in case of an error

Header

vca_od.h

Name

vcaod_set_value — copies object value from caller's buffer to Object Dictionary

Synopsisint vcaod_set_value (object, array_index, buff, len, abort_code); vcaod_object_t*

object;

int array_index;const void * buff;int len;uint32_t * abort_code;

Arguments

objectobject from dictionary, see. vcaod_find_object

array_indexif object is an array, array_index, tells which item to get, in other case it issimply ignored.

buffbuffer containing written data

lenlength of the data

abort_codearea to fill the abort code in case of an ERROR. It can be NULL, than it isignored. Abort codes are defined in CANopen standart 301 and can betranslated to text calling vcasdo_abort_msg.

Description

Function sets whole buffer to zeros before it starts to copy object data to it, evenif buffer is larger than data.

Page 238: WP10 -D10.8 Programmer's Guide - MNIS

Return

number of stored data bytes negative value in case of an error

Header

vca_od.h

Name

vcaod_get_object_data_size — get size of object in bytes

Synopsisint vcaod_get_object_data_size (object, abort_code); const vcaod_object_t *

object;

uint32_t * abort_code;

Arguments

objectobject from dictionary, see. vcaod_find_object

abort_codearea to fill the abort code in case of an ERROR. It can be NULL, than it isignored. Abort codes are defined in CANopen standart 301 and can betranslated to text calling vcasdo_abort_msg.

Return

number of stored data bytes negative value in case of an error

Header

vca_od.h

Name

od_item_set_value_as_str — set object value from its string representation.

Synopsisint od_item_set_value_as_str ( item, valstr); vcaod_object_t *

item;

const char* valstr;

Page 239: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

itemobject to set

valstrstring representation of object value

Return

negative value in case of an error

Header

vca_od.h

Name

vcaod_od_free — release all OD memory

Synopsis

void vcaod_od_free (odroot);vcaod_root_t * odroot;

Arguments

odrootpointer to the object dictionary root

Header

vca_od.h

Name

vcaod_dump_od — debug function, dumps OD to log

Synopsis

void vcaod_dump_od (odroot);vcaod_root_t * odroot;

Arguments

odrootroot, which contains OD

Header

vca_od.h

Page 240: WP10 -D10.8 Programmer's Guide - MNIS

Name

vcaod_get_dinfo_ref — returns reference to dinfo corresponting to obj

Synopsissui_dinfo_t * vcaod_get_dinfo_ref (obj, create_weak); vcaod_object_t *

obj;

int create_weak;

Arguments

objobject from OD

create_weakif there is no HW dinfo for object, creates temporary dbuff dinfo

Description

If obj allready has its &dinfo assigned vcaod_get_dinfo_ref returns thispointer, if it is not function creates new &dinfo object.

Return

pointer to associated dinfo with reference count increased or NULL if creationfails

Header

vca_od.h

2.5) libulut API

Name

ul_dbuff_init — init memory allocated for dynamic buffer

Synopsisint ul_dbuff_init (buf, flags); ul_dbuff_t *

buf;

int flags;

Page 241: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

bufbuffer structure

flagsflags describing behaviour of the buffer only UL_DBUFF_IS_STATIC flag issupported. in this case buffer use unly static array sbuf

Description

Returns capacity of initialised buffer

Name

ul_dbuff_destroy — frees all resources allocated by buf

Synopsis

void ul_dbuff_destroy (buf);ul_dbuff_t * buf;

Arguments

bufbuffer structure

Name

ul_dbuff_prep — sets a new len and capacity of the buffer

Synopsisint ul_dbuff_prep (buf, new_len); ul_dbuff_t *

buf;

int new_len;

Arguments

bufbuffer structure

new_lennew desired buffer length

Description

Returns new buffer length

Page 242: WP10 -D10.8 Programmer's Guide - MNIS

Name

struct ul_dbuff_t — Generic Buffer for Dynamic Data

Synopsisstruct ul_dbuff_t { unsigned long len; unsigned long capacity; int flags; unsigned char * data; unsigned char * sbuff;};

Members

lenactual length of stored data

capacitycapacity of allocated buffer

flagsonly one flag (UL_DBUFF_IS_STATIC) used now

datapointer to dynamically allocated buffer

sbuffstatic buffer for small data sizes

Name

ul_dbuff_set_capacity — change capacity of buffer to at least new_capacity

Synopsisint ul_dbuff_set_capacity (buf, new_capacity); ul_dbuff_t *

buf;

int new_capacity;

Arguments

bufbuffer structure

new_capacitynew capacity

Description

Returns real capacity of reallocated buffer

Page 243: WP10 -D10.8 Programmer's Guide - MNIS

Name

ul_dbuff_set_len — sets a new len of the buffer, change the capacity ifneccessary

Synopsisint ul_dbuff_set_len (buf, new_len); ul_dbuff_t *

buf;

int new_len;

Arguments

bufbuffer structure

new_lennew desired buffer length

Description

Returns new buffer length

Name

ul_dbuff_set — copies bytes to buffer and change its capacity if neccessary likememset

Synopsisint ul_dbuff_set (buf, b, n); ul_dbuff_t *

buf;

byte b;int n;

Arguments

bufbuffer structure

bappended bytes

nnumber of apended bytes

Page 244: WP10 -D10.8 Programmer's Guide - MNIS

Returns

length of buffer

Name

ul_dbuff_cpy — copies bytes to buffer and change its capacity if neccessary

Synopsisint ul_dbuff_cpy (buf, b, n); ul_dbuff_t * buf;const void * b;int n;

Arguments

bufbuffer structure

bappended bytes

nnumber of apended bytes

Returns

length of buffer

Name

ul_dbuff_cat — appends bytes at end of buffer and change its capacity ifneccessary

Synopsisint ul_dbuff_cat (buf, b, n); ul_dbuff_t * buf;const void * b;int n;

Arguments

bufbuffer structure

b

Page 245: WP10 -D10.8 Programmer's Guide - MNIS

appended bytesn

number of apended bytes

Returns

length of buffer

Name

ul_dbuff_strcat — appends str at dhe end of buffer and change its capacity ifneccessary

Synopsisint ul_dbuff_strcat (buf, str); ul_dbuff_t * buf;const char * str;

Arguments

bufbuffer structure

strstring to append

Description

Returns number length of buffer (including terminating '\0')

Name

ul_dbuff_strcpy — copy str to the buffer and change its capacity if neccessary

Synopsisint ul_dbuff_strcpy (buf, str); ul_dbuff_t * buf;const char * str;

Arguments

bufbuffer structure

strstring to copy

Page 246: WP10 -D10.8 Programmer's Guide - MNIS

Description

Returns number length of buffer (including terminating '\0')

Name

ul_dbuff_append_byte — appends byte at dhe end of buffer and change itscapacity if neccessary

Synopsisint ul_dbuff_append_byte (buf, b); ul_dbuff_t * buf;unsigned char b;

Arguments

bufbuffer structure

bappended byte

Description

Returns number length of buffer (including terminating '\0')

Name

ul_dbuff_ltrim — remove all white space characters from the left

Synopsis

int ul_dbuff_ltrim (buf);ul_dbuff_t * buf;

Arguments

bufbuffer structure

Return

new length of buffer

Name

ul_dbuff_rtrim — remove all white space characters from the right

Page 247: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis

int ul_dbuff_rtrim (buf);ul_dbuff_t * buf;

Arguments

bufbuffer structure

Description

if buffer is terminated by '\0', than is also terminated after rtrim

Return

new length of buffer

Name

ul_dbuff_trim — remove all white space characters from the right and from theleft

Synopsis

int ul_dbuff_trim (buf);ul_dbuff_t * buf;

Arguments

bufbuffer structure

Description

Returns number length of buffer (including terminating '\0')

Name

ul_dbuff_cpos — searches string for char

Synopsisint ul_dbuff_cpos (buf, what, quote); const ul_dbuff_t *

buf;

unsigned char what;unsigned char quote;

Page 248: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

bufsearched dbuff

whatchar to find

quoteskip str areas quoted in quote chars<br> If you want to ignore quotesassign '\0' to quote in function call

Return

position of what char or negative value

Name

ul_str_cpos — searches string for char

Synopsisint ul_str_cpos (str, what, quote); const unsigned char * str;unsigned char what;unsigned char quote;

Arguments

strzero terminated string

whatchar to find

quoteskip str areas quoted in quote chars If you want to ignore quotes assign '\0'to quote in function call

Return

position of what char or negative value

Name

ul_str_pos — searches string for substring

Synopsisint ul_str_pos (str, what,

Page 249: WP10 -D10.8 Programmer's Guide - MNIS

quote); const unsigned char * str;const unsigned char * what;unsigned char quote;

Arguments

strzero terminated string

whatstring to find

quoteskip str areas quoted in quote chars If you want to ignore quotes assign '\0'to quote in function call

Return

position of what string or negative value

Name

ul_str_ncpy — copies string to the buffer

Synopsisint ul_str_ncpy ( to, from, buff_size); unsigned char * to;const unsigned char * from;int buff_size;

Arguments

tobuffer where to copy str

fromzero terminated string

buff_sizesize of the to buffer (including terminating zero)

Description

Standard strncpy function have some disadvatages (ie. do not append term. zeroif copied string doesn't fit in to buffer, fills whole rest of buffer with zeros)

Returns strlen(to) or negative value in case of error

Page 250: WP10 -D10.8 Programmer's Guide - MNIS

Name

ul_dbuff_log_hex — writes content of dbuff to log

Synopsisvoid ul_dbuff_log_hex (buf,

log_level);

ul_dbuff_t *

buf;

int log_level;

Arguments

bufbuffer structure

log_levellogging level

Name

ul_dbuff_cut_pos — cut first n bytes from fromdb and copies it to todb.

Synopsisvoid ul_dbuff_cut_pos ( fromdb, todb, n); ul_dbuff_t *

fromdb;

ul_dbuff_t *

todb;

int n;

Arguments

fromdbbuffer to cut from

todbbuffer to copy to

nposition where to cut

Description

If n is greater than fromdb.len whole fromdb is copied to todb. If n is negativeposition to cut is counted from the end of fromdb. If n is zero fromdb staysunchanged and todb is resized to len equal zero.

Page 251: WP10 -D10.8 Programmer's Guide - MNIS

Name

ul_dbuff_cut_delimited — cuts bytes before delimiter + delimiter char fromfromdb and copies tham to the todb

Synopsisvoid ul_dbuff_cut_delimited ( fromdb, todb, delimiter, quote); ul_dbuff_t *

fromdb;

ul_dbuff_t *

todb;

char delimiter;char quote;

Arguments

fromdbbuffer to cut from

todbbuffer to copy to

delimiterdelimiter char

quotequoted delimiters are ignored, quote can be '\0', than it is ignored.

Description

If fromdb doesn't contain delimiter todb is trimmed to zero length.

Name

ul_dbuff_cut_token — cuts not whitespaces from fromdb to todb.

Synopsisvoid ul_dbuff_cut_token ( fromdb, todb); ul_dbuff_t *

fromdb;

ul_dbuff_t *

todb;

Page 252: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

fromdbbuffer to cut from

todbbuffer to copy to

Description

Leading whitespaces are ignored. Cut string is trimmed.

Name

evc_link_init — Initialize Event Connector Link

Synopsis

int evc_link_init (link);evc_link_t * link;

Arguments

linkpointer to the link

Description

Link reference count is set to 1 by this function

Return Value

negative value informs about failure.

Name

evc_link_new — Allocates New Event Connector Link

Synopsis

evc_link_t * evc_link_new (void);void;

Arguments

voidno arguments

Description

Link reference count is set to 1 by this function

Page 253: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

pointer to the new link or NULL.

Name

evc_link_connect — Connects Link between Two Hubs

Synopsisint evc_link_connect ( link, src, dst, prop); evc_link_t * link;evc_tx_hub_t * src;evc_rx_hub_t * dst;evc_prop_fnc_t * prop;

Arguments

linkpointer to the non-connected initialized link

srcpointer to the source hub of type &evc_tx_hub_t

dstpointer to the destination hub of type &evc_rx_hub_t

proppropagation function corresponding to source and destination expectedevent arguments

Description

If ready flag is not set, link state is set to ready and reference count is increased.

Return Value

negative return value indicates fail.

Name

evc_link_init_standalone — Initialize Standalone Link

Synopsisint evc_link_init_standalone ( link, rx_fnc, context); evc_link_t * link;

Page 254: WP10 -D10.8 Programmer's Guide - MNIS

evc_rx_fnc_t * rx_fnc;void * context;

Arguments

linkpointer to the link

rx_fncpointer to the function invoked by event reception

contextcontext for the rx_fnc function invocation

Description

Link reference count is set to 1 by this function

Return Value

negative value informs about failure.

Name

evc_link_new_standalone — Allocates New Standalone Link

Synopsisevc_link_t * evc_link_new_standalone (rx_fnc, context); evc_rx_fnc_t * rx_fnc;void * context;

Arguments

rx_fnccallback function invoked if event is delivered

contextcontext provided to the callback function

Description

Link reference count is set to 1 by this function

Return Value

pointer to the new link or NULL.

Name

evc_link_connect_standalone — Connects Standalone Link to Source Hubs

Page 255: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint evc_link_connect_standalone ( link, src, prop); evc_link_t * link;evc_tx_hub_t * src;evc_prop_fnc_t * prop;

Arguments

linkpointer to the non-connected initialized link

srcpointer to the source hub of type &evc_tx_hub_t

proppropagation function corresponding to hub source and standalone rx_fncexpected event arguments

Description

If ready flag is not set, link state is set to ready and reference count is increased.

Return Value

negative return value indicates failure.

Name

evc_link_delete — Deletes Link from Hubs Lists

Synopsis

int evc_link_delete (link);evc_link_t * link;

Arguments

linkpointer to the possibly connected initialized link

Description

If ready flag is set, link ready flag is cleared and reference count is decreased.This could lead to link disappear, if nobody is holding reference.

Return Value

positive return value indicates immediate delete, zero return value informs aboutdelayed delete.

Page 256: WP10 -D10.8 Programmer's Guide - MNIS

Name

evc_link_dispose — Disposes Link

Synopsis

void evc_link_dispose (link);evc_link_t * link;

Arguments

linkpointer to the possibly connected initialized link

Description

Deletes link from hubs, marks it as dead, calls final death propagate for the linkand if link is malloced, releases link occupied memory.

Name

evc_tx_hub_init — Initializes Event Transmition Hub

Synopsis

int evc_tx_hub_init (hub);evc_tx_hub_t * hub;

Arguments

hubpointer to the &evc_tx_hub_t type hub

Return Value

negative return value indicates failure.

Name

evc_tx_hub_done — Initializes Event Transmition Hub

Synopsis

void evc_tx_hub_done (hub);evc_tx_hub_t * hub;

Page 257: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

hubpointer to the &evc_tx_hub_t type hub

Name

evc_tx_hub_propagate — Propagate Event to Links Destinations

Synopsisvoid evc_tx_hub_propagate (hub, args); evc_tx_hub_t *

hub;

va_list args;

Arguments

hubpointer to the &evc_tx_hub_t type hub

argspointer to the variable arguments list

Description

The function propagates event to the connected links, it skips links marked asdead, blocked or delete_pend. If the link is not marked as recursive, itensures, that link is not called twice.

Name

evc_tx_hub_emit — Emits Event to Hub

Synopsisvoid evc_tx_hub_emit (hub, ...); evc_tx_hub_t *

hub;

... ...;

Arguments

hubpointer to the &evc_tx_hub_t type hub

...variable arguments

Page 258: WP10 -D10.8 Programmer's Guide - MNIS

Description

The function hands over arguments to evc_tx_hub_propagate as &va_list.

Name

evc_rx_hub_init — Initializes Event Receiption Hub

Synopsisint evc_rx_hub_init (hub, rx_fnc, context); evc_rx_hub_t *

hub;

evc_rx_fnc_t * rx_fnc;void * context;

Arguments

hubpointer to the &evc_rx_hub_t type hub

rx_fncpointer to the function invoked by event reception

contextcontext for the rx_fnc function invocation

Return Value

negative return value indicates failure.

Name

evc_rx_hub_done — Finalize Event Receiption Hub

Synopsis

void evc_rx_hub_done (hub);evc_rx_hub_t * hub;

Arguments

hubpointer to the &evc_rx_hub_t type hub

Name

struct evc_link — Event Connector Link

Page 259: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisstruct evc_link { struct dst; evc_prop_fnc_t * propagate; int refcnt; unsigned recursive:1; unsigned blocked:1; unsigned ready:1; unsigned dead:1; unsigned delete_pend:1; unsigned malloced:1; unsigned standalone:1; unsigned tx_full_hub:1; unsigned rx_full_hub:1; short taken;};

Members

dstdetermines destination of the event, it can be standalone rx_fncfunction with with context or &evc_tx_hub_t in the multi case

propagatepointer to the arguments propagation function,

refcntlink reference counter

recursivelink can propagate could be invoked recursively, else recursive events areignored by link

blockedevent propagation is blocked for the link, can be used by application

readylink is ready and has purpose to live - it connects two active entities

deadlink is dead and cannot propagate events

delete_pendlink is being deleted, but it is taken simultaneously, delete has to wait forfinish of the propagate and to moving to the next link

mallocedlink has been malloced and should be automatically freed when referenccounts drop to zero

standalonelink is used for standalone function invocation

tx_full_hubsrc points to the full hub structure

rx_full_hubdst points to the full hub structure

takenlink is in middle of the propagation process

Page 260: WP10 -D10.8 Programmer's Guide - MNIS

Description

The link delivers events from the source to the destination. The link specificfunction propagate is called for each link leading from the hub activated byevc_tx_hub_emit and evc_tx_hub_propagate. The propagate function isresponsible for parameters transformation before invocation of standalone ordestination hub rx_fnc function.

Name

struct evc_tx_hub — Event Transmit Hub

Synopsisstruct evc_tx_hub { ul_list_head_t links;};

Members

linkslist of links outgoing from the hub

Name

struct evc_rx_hub — Event Receiving Hub

Synopsisstruct evc_rx_hub { ul_list_head_t links; evc_rx_fnc_t * rx_fnc; void * context;};

Members

linkslist of links incoming to the hub

rx_fncfunction invoked when event arives

contextcontext for rx_fnc

Name

evc_link_inc_refcnt — Increment Link Reference Count

Page 261: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisvoid evc_link_inc_refcnt ( link); evc_link_t *

link;

Arguments

linkpointer to link

Name

evc_link_dec_refcnt — Decrement Link Reference Count

Synopsisvoid evc_link_dec_refcnt ( link); evc_link_t *

link;

Arguments

linkpointer to link

Description

if the link reference count drops to 0, link is deleted from hubs byevc_link_dispose function and if malloced is sed, link memory is disposedby free. Special handlink can be achieved if propagate returns non-zero valueif called with ded link.

Name

gavl_first_node — Returns First Node of GAVL Tree

Synopsisgavl_node_t * gavl_first_node (root); const gavl_root_t *

root;

Arguments

rootGAVL tree root

Page 262: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

pointer to the first node of tree according to ordering

Name

gavl_last_node — Returns Last Node of GAVL Tree

Synopsisgavl_node_t * gavl_last_node (root); const gavl_root_t *

root;

Arguments

rootGAVL tree root

Return Value

pointer to the last node of tree according to ordering

Name

gavl_is_empty — Check for Empty GAVL Tree

Synopsisint gavl_is_empty (root); const gavl_root_t *

root;

Arguments

rootGAVL tree root

Return Value

returns non-zero value if there is no node in the tree

Name

gavl_search_node — Search for Node or Place for Node by Key

Synopsisint gavl_search_node (root,

Page 263: WP10 -D10.8 Programmer's Guide - MNIS

key, mode, nodep); const gavl_root_t *

root;

const void * key;int mode;gavl_node_t ** nodep;

Arguments

rootGAVL tree root

keykey value searched for

modemode of the search operation

nodeppointer to place for storing of pointer to found node or pointer to node whichshould be parent of inserted node

Description

Core search routine for GAVL trees searches in tree starting at root for node ofitem with value of item field at offset key_off equal to provided *key value.Values are compared by function pointed by *cmp_fnc field in the tree root.Integer mode modifies search algorithm: GAVL_FANY .. finds node of any itemwith field value *key, GAVL_FFIRST .. finds node of first item with *key,GAVL_FAFTER .. node points after last item with *key value, reworded - indexpoints at first item with higher value of field or after last item

Return Value

Return of nonzero value indicates match found. If the mode is ored withGAVL_FCMP, result of last compare is returned.

Name

gavl_find — Find Item for Provided Key

Synopsisvoid * gavl_find (root, key); const gavl_root_t *

root;

const void * key;

Page 264: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

rootGAVL tree root

keykey value searched for

Return Value

pointer to item associated to key value.

Name

gavl_find_first — Find the First Item with Provided Key Value

Synopsisvoid * gavl_find_first (root, key); const gavl_root_t *

root;

const void * key;

Arguments

rootGAVL tree root

keykey value searched for

Description

same as above, but first matching item is found.

Return Value

pointer to the first item associated to key value.

Name

gavl_find_after — Find the First Item with Higher Key Value

Synopsisvoid * gavl_find_after (root, key); const gavl_root_t *

root;

const void * key;

Page 265: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

rootGAVL tree root

keykey value searched for

Description

same as above, but points to item with first key value above searched key.

Return Value

pointer to the first item associated to key value.

Name

gavl_insert_node_at — Insert Existing Node to Already Computed Place intoGAVL Tree

Synopsisint gavl_insert_node_at (root, node, where, leftright); gavl_root_t * root;gavl_node_t *

node;

gavl_node_t *

where;

int leftright;

Arguments

rootGAVL tree root

nodepointer to inserted node

wherepointer to found parent node

leftrightleft (1) or right (0) branch

Return Value

positive value informs about success

Page 266: WP10 -D10.8 Programmer's Guide - MNIS

Name

gavl_insert_node — Insert Existing Node into GAVL Tree

Synopsisint gavl_insert_node (root, node, mode); gavl_root_t * root;gavl_node_t *

node;

int mode;

Arguments

rootGAVL tree root

nodepointer to inserted node

modeif mode is GAVL_FAFTER, multiple items with same key can be used, elsestrict ordering is required

Return Value

positive value informs about success

Name

gavl_insert — Insert New Item into GAVL Tree

Synopsisint gavl_insert (root, item, mode); gavl_root_t *

root;

void * item;int mode;

Arguments

rootGAVL tree root

itempointer to inserted item

mode

Page 267: WP10 -D10.8 Programmer's Guide - MNIS

if mode is GAVL_FAFTER, multiple items with same key can be used, elsestrict ordering is required

Return Value

positive value informs about success, negative value indicates malloc fail orattempt to insert item with already defined key.

Name

gavl_delete_node — Deletes/Unlinks Node from GAVL Tree

Synopsisint gavl_delete_node (root, node); gavl_root_t * root;gavl_node_t *

node;

Arguments

rootGAVL tree root

nodepointer to deleted node

Return Value

positive value informs about success.

Name

gavl_delete — Delete/Unlink Item from GAVL Tree

Synopsisint gavl_delete (root, item); gavl_root_t *

root;

void * item;

Arguments

rootGAVL tree root

itempointer to deleted item

Page 268: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

positive value informs about success, negative value indicates that item is notfound in tree defined by root

Name

gavl_delete_and_next_node — Delete/Unlink Item from GAVL Tree

Synopsisgavl_node_t * gavl_delete_and_next_node (root, node); gavl_root_t * root;gavl_node_t *

node;

Arguments

rootGAVL tree root

nodepointer to actual node which is unlinked from tree after function call, it canbe unalocated or reused by application code after this call.

Description

This function can be used after call gavl_first_node for destructive traversalthrough the tree, it cannot be combined with gavl_next_node orgavl_prev_node and root is emptied after the end of traversal. If the tree isused after unsuccessful/unfinished traversal, it must be balanced again. Theheight differences are inconsistent in other case. If traversal could be interrupted,the function gavl_cut_first could be better choice.

Return Value

pointer to next node or NULL, when all nodes are deleted

Name

gavl_cut_first — Cut First Item from Tree

Synopsis

void * gavl_cut_first (root);gavl_root_t * root;

Page 269: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

rootGAVL tree root

Description

This enables fast delete of the first item without tree balancing. The resulting treeis degraded but height differences are kept consistent. Use of this function canresult in height of tree maximally one greater the tree managed by optimal AVLfunctions.

Return Value

returns the first item or NULL if the tree is empty

Name

struct gavl_node — Structure Representing Node of Generic AVL Tree

Synopsisstruct gavl_node { struct gavl_node * left; struct gavl_node * right; struct gavl_node * parent; int hdiff;};

Members

leftpointer to left child or NULL

rightpointer to right child or NULL

parentpointer to parent node, NULL for root

hdiffdifference of height between left and right child

Description

This structure represents one node in the tree and links left and right tonodes with lower and higher value of order criterion. Each tree is built from onetype of items defined by user. User can decide to include node structure insideitem representation or GAVL can malloc node structures for each inserted item.The GAVL allocates memory space with capacity sizeof(gavl_node_t)+sizeof(void*) in the second case. The item pointer is stored following node structure(void**)(node+1);

Page 270: WP10 -D10.8 Programmer's Guide - MNIS

Name

struct gavl_root — Structure Representing Root of Generic AVL Tree

Synopsisstruct gavl_root { gavl_node_t * root_node; int node_offs; int key_offs; gavl_cmp_fnc_t * cmp_fnc;};

Members

root_nodepointer to root node of GAVL tree

node_offsoffset between start of user defined item representation and included GAVLnode structure. If negative value is stored there, user item does not containnode structure and GAVL manages standalone ones with item pointers.

key_offsoffset to compared (ordered) fields in the item representation

cmp_fncfunction defining order of items by comparing fields at offset key_offs.

Name

gavl_node2item — Conversion from GAVL Tree Node to User Defined Item

Synopsisvoid * gavl_node2item (root, node); const gavl_root_t * root;const gavl_node_t *

node;

Arguments

rootGAVL tree root

nodenode belonging to root GAVL tree

Return Value

pointer to item corresponding to node

Page 271: WP10 -D10.8 Programmer's Guide - MNIS

Name

gavl_node2item_safe — Conversion from GAVL Tree Node to User Defined Item

Synopsisvoid * gavl_node2item_safe (root, node); const gavl_root_t * root;const gavl_node_t *

node;

Arguments

rootGAVL tree root

nodenode belonging to root GAVL tree

Return Value

pointer to item corresponding to node

Name

gavl_node2key — Conversion from GAVL Tree Node to Ordering Key

Synopsisvoid * gavl_node2key (root, node); const gavl_root_t * root;const gavl_node_t *

node;

Arguments

rootGAVL tree root

nodenode belonging to root GAVL tree

Return Value

pointer to key corresponding to node

Name

gavl_next_node — Returns Next Node of GAVL Tree

Page 272: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisgavl_node_t * gavl_next_node (node); const gavl_node_t *

node;

Arguments

nodenode for which accessor is looked for

Return Value

pointer to next node of tree according to ordering

Name

gavl_prev_node — Returns Previous Node of GAVL Tree

Synopsisgavl_node_t * gavl_prev_node (node); const gavl_node_t *

node;

Arguments

nodenode for which predecessor is looked for

Return Value

pointer to previous node of tree according to ordering

Name

gavl_balance_one — Balance One Node to Enhance Balance Factor

Synopsisint gavl_balance_one (subtree); gavl_node_t **

subtree;

Arguments

subtreepointer to pointer to node for which balance is enhanced

Page 273: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

returns nonzero value if height of subtree is lowered by one

Name

gavl_insert_primitive_at — Low Lewel Routine to Insert Node into Tree

Synopsisint gavl_insert_primitive_at (root_nodep, node, where, leftright); gavl_node_t **

root_nodep;

gavl_node_t * node;gavl_node_t * where;int leftright;

Arguments

root_nodeppointer to pointer to GAVL tree root node

nodepointer to inserted node

wherepointer to found parent node

leftrightleft (>=1) or right (<=0) branch

Description

This function can be used for implementing AVL trees with custom rootdefinition. The value of the selected left or right pointer of provided nodehas to be NULL before insert operation, i.e. node has to be end node in theselected direction.

Return Value

positive value informs about success

Name

gavl_delete_primitive — Low Lewel Deletes/Unlinks Node from GAVL Tree

Synopsisint gavl_delete_primitive (root_nodep,

Page 274: WP10 -D10.8 Programmer's Guide - MNIS

node); gavl_node_t **

root_nodep;

gavl_node_t * node;

Arguments

root_nodeppointer to pointer to GAVL tree root node

nodepointer to deleted node

Return Value

positive value informs about success.

Name

gavl_cut_first_primitive — Low Lewel Routine to Cut First Node from Tree

Synopsis

gavl_node_t * gavl_cut_first_primitive (root_nodep);

gavl_node_t **

root_nodep;

Arguments

root_nodeppointer to pointer to GAVL tree root node

Description

This enables fast delete of the first node without tree balancing. The resultingtree is degraded but height differences are kept consistent. Use of this functioncan result in height of tree maximally one greater the tree managed by optimalAVL functions.

Return Value

returns the first node or NULL if the tree is empty

Name

gsa_struct_init — Initialize GSA Structure

Page 275: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisvoid gsa_struct_init (array, key_offs, cmp_fnc); gsa_array_t * array;int key_offs;gsa_cmp_fnc_t * cmp_fnc;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

key_offsoffset to the order controlling field obtained by UL_OFFSETOF

cmp_fncfunction defining order of items by comparing fields at offset key_offs.

Name

gsa_delete_all — Delete Pointers to the All Items in the Array

Synopsis

void gsa_delete_all (array);gsa_array_t * array;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

Description

This function releases all internally allocated memory, but does not releasememory of the array structure

Name

gsa_bsearch_indx — Search for Item or Place for Item by Key

Synopsisint gsa_bsearch_indx (array, key, key_offs, cmp_fnc, mode, indx);

Page 276: WP10 -D10.8 Programmer's Guide - MNIS

gsa_array_t * array;void * key;int key_offs;gsa_cmp_fnc_t * cmp_fnc;int mode;unsigned * indx;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

keykey value searched for

key_offsoffset to the order controlling field obtained by UL_OFFSETOF

cmp_fncfunction defining order of items by comparing fields

modemode of the search operation

indxpointer to place, where store value of found item array index or index wherenew item should be inserted

Description

Core search routine for GSA arrays binary searches for item with field at offsetkey_off equal to key value Values are compared by function pointed by*cmp_fnc field in the array structure array. Integer mode modifies searchalgorithm: GSA_FANY .. finds item with field value *key, GSA_FFIRST .. finds thefirst item with field value *key, GSA_FAFTER .. index points after last item with*key value, reworded - index points at first item with higher value of field or afterlast item

Return Value

Return of nonzero value indicates match found.

Name

gsa_find — Find Item for Provided Key

Synopsisvoid * gsa_find (array, key); gsa_array_t * array;void * key;

Page 277: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

keykey value searched for

Return Value

pointer to item associated to key value or NULL.

Name

gsa_find_first — Find the First Item for Provided Key

Synopsisvoid * gsa_find_first (array, key); gsa_array_t * array;void * key;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

keykey value searched for

Description

same as above, but first matching item is found.

Return Value

pointer to the first item associated to key value or NULL.

Name

gsa_find_indx — Find the First Item with Key Value and Return Its Index

Synopsisvoid * gsa_find_indx (array, key, indx); gsa_array_t * array;void * key;int * indx;

Page 278: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

keykey value searched for

indxpointer to place for index, at which new item should be inserted

Description

same as above, but additionally stores item index value.

Return Value

pointer to the first item associated to key value or NULL.

Name

gsa_insert_at — Insert Existing Item to the Specified Array Index

Synopsisint gsa_insert_at (array, item, where); gsa_array_t * array;void * item;unsigned where;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

itempointer to inserted Item

whereat which index should be item inserted

Return Value

positive or zero value informs about success

Name

gsa_insert — Insert Existing into Ordered Item Array

Page 279: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint gsa_insert (array, item, mode); gsa_array_t * array;void * item;int mode;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

itempointer to inserted Item

modeif mode is GSA_FAFTER, multiple items with same key can be stored intoarray, else strict ordering is required

Return Value

positive or zero value informs about success

Name

gsa_delete_at — Delete Item from the Specified Array Index

Synopsisint gsa_delete_at (array, indx); gsa_array_t * array;unsigned indx;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

indxindex of deleted item

Return Value

positive or zero value informs about success

Name

gsa_delete — Delete Item from the Array

Page 280: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint gsa_delete (array, item); gsa_array_t * array;void * item;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

itempointer to deleted Item

Return Value

positive or zero value informs about success

Name

gsa_resort_buble — Sort Again Array If Sorting Criteria Are Changed

Synopsisint gsa_resort_buble (array, key_offs, cmp_fnc); gsa_array_t * array;int key_offs;gsa_cmp_fnc_t * cmp_fnc;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

key_offsoffset to the order controlling field obtained by UL_OFFSETOF

cmp_fncfunction defining order of items by comparing fields

Return Value

non-zero value informs, that resorting changed order

Name

gsa_setsort — Change Array Sorting Criterion

Page 281: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisint gsa_setsort (array, key_offs, cmp_fnc); gsa_array_t * array;int key_offs;gsa_cmp_fnc_t * cmp_fnc;

Arguments

arraypointer to the array structure declared through GSA_ARRAY_FOR

key_offsnew value of offset to the order controlling field

cmp_fncnew function defining order of items by comparing fields at offsetkey_offs

Return Value

non-zero value informs, that resorting changed order

Name

struct gsa_array_field_t — Structure Representing Anchor of ustom GSA Array

Synopsisstruct gsa_array_field_t { void ** items; unsigned count; unsigned alloc_count;};

Members

itemspointer to array of pointers to individual items

countnumber of items in the sorted array

alloc_countallocated pointer array capacity

Name

struct ul_htim_node — Timer queue entry base structure

Page 282: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisstruct ul_htim_node { #elseul_hpt_node_t node; #elseul_hpt_node_t node; #endiful_htim_time_t expires;};

Members

noderegular GAVL node structure for insertion into

noderegular GAVL node structure for insertion into

expirestime to trigger timer in &ul_htim_time_t type defined resolution

Description

This is basic type useful to define more complete timer types

Name

struct ul_htim_queue — Timer queue head/root base structure

Synopsisstruct ul_htim_queue { #elseul_hpt_root_field_t timers; #elseul_hpt_root_field_t timers; #endifint first_changed;};

Members

timersroot of FLES GAVL tree of timer entries

timersroot of FLES GAVL tree of timer entries

first_changedflag, which is set after each add, detach operation which concerning offirsts scheduled timer

Description

This is basic type useful to define more complete timer queues types

Name

struct ul_htimer — Standard timer entry with callback function

Page 283: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisstruct ul_htimer { ul_htim_node_t htim; ul_htimer_fnc_t * function; unsigned long data;};

Members

htimbasic timer queue entry

functionuser provided function to call at trigger time

datauser selected data

Description

This is standard timer type, which requires data casting in many cases. Thetype of function field has to be declared in “ul_htimdefs.h” header file.

Name

struct ul_htimer_queue — Standard timer queue

Synopsisstruct ul_htimer_queue { ul_htim_queue_t htim_queue;};

Members

htim_queuethe structure wraps &ul_htim_queue structure

Description

This is standard timer type, which requires data casting in many cases

Name

list_add — add a new entry

Synopsisvoid list_add (new, head);

Page 284: WP10 -D10.8 Programmer's Guide - MNIS

struct list_head *

new;

struct list_head *

head;

Arguments

newnew entry to be added

headlist head to add it after

Description

Insert a new entry after the specified head. This is good for implementing stacks.

Name

list_add_tail — add a new entry

Synopsisvoid list_add_tail (new, head); struct list_head *

new;

struct list_head *

head;

Arguments

newnew entry to be added

headlist head to add it before

Description

Insert a new entry before the specified head. This is useful for implementingqueues.

Name

list_del — deletes entry from list.

Synopsis

void list_del (entry);struct list_head * entry;

Page 285: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

entrythe element to delete from the list.

Note

list_empty on entry does not return true after this, the entry is in an undefinedstate.

Name

list_del_init — deletes entry from list and reinitialize it.

Synopsisvoid list_del_init (entry); struct list_head *

entry;

Arguments

entrythe element to delete from the list.

Name

list_move — delete from one list and add as another's head

Synopsisvoid list_move ( list, head); struct list_head *

list;

struct list_head *

head;

Arguments

listthe entry to move

headthe head that will precede our entry

Name

list_move_tail — delete from one list and add as another's tail

Page 286: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisvoid list_move_tail ( list, head); struct list_head *

list;

struct list_head *

head;

Arguments

listthe entry to move

headthe head that will follow our entry

Name

list_empty — tests whether a list is empty

Synopsis

int list_empty (head);struct list_head * head;

Arguments

headthe list to test.

Name

list_splice — join two lists

Synopsisvoid list_splice ( list, head); struct list_head *

list;

struct list_head *

head;

Arguments

listthe new list to add.

headthe place to add it in the first list.

Page 287: WP10 -D10.8 Programmer's Guide - MNIS

Name

list_splice_init — join two lists and reinitialise the emptied list.

Synopsisvoid list_splice_init ( list, head); struct list_head *

list;

struct list_head *

head;

Arguments

listthe new list to add.

headthe place to add it in the first list.

Description

The list at list is reinitialised

Name

list_entry — get the struct for this entry

Synopsis

list_entry (ptr, type, member);ptr;type;member;

Arguments

ptrthe &struct list_head pointer.

typethe type of the struct this is embedded in.

memberthe name of the list_struct within the struct.

Name

list_for_each — iterate over a list

Page 288: WP10 -D10.8 Programmer's Guide - MNIS

Synopsis

list_for_each (pos, head);pos;head;

Arguments

posthe &struct list_head to use as a loop counter.

headthe head for your list.

Name

__list_for_each — iterate over a list

Synopsis

__list_for_each (pos, head);pos;head;

Arguments

posthe &struct list_head to use as a loop counter.

headthe head for your list.

Description

This variant differs from list_for_each in that it's the simplest possible listiteration code, no prefetching is done. Use this for code that knows the list to bevery short (empty or 1 entry) most of the time.

Name

list_for_each_prev — iterate over a list backwards

Synopsis

list_for_each_prev (pos, head);pos;head;

Arguments

pos

Page 289: WP10 -D10.8 Programmer's Guide - MNIS

the &struct list_head to use as a loop counter.head

the head for your list.

Name

list_for_each_safe — iterate over a list safe against removal of list entry

Synopsis

list_for_each_safe (pos, n, head);pos;n;head;

Arguments

posthe &struct list_head to use as a loop counter.

nanother &struct list_head to use as temporary storage

headthe head for your list.

Name

list_for_each_entry — iterate over list of given type

Synopsis

list_for_each_entry (pos, head, member);pos;head;member;

Arguments

posthe type * to use as a loop counter.

headthe head for your list.

memberthe name of the list_struct within the struct.

Name

list_for_each_entry_reverse — iterate backwards over list of given type.

Page 290: WP10 -D10.8 Programmer's Guide - MNIS

Synopsislist_for_each_entry_reverse (pos, head, member); pos; head; member;

Arguments

posthe type * to use as a loop counter.

headthe head for your list.

memberthe name of the list_struct within the struct.

Name

list_for_each_entry_safe — iterate over list of given type safe against removal oflist entry

Synopsis

list_for_each_entry_safe (pos, n, head, member);pos;n;head;member;

Arguments

posthe type * to use as a loop counter.

nanother type * to use as temporary storage

headthe head for your list.

memberthe name of the list_struct within the struct.

2.6) libsuiut API

Name

sui_dinfo_inc_refcnt — Increase reference count of DINFO

Page 291: WP10 -D10.8 Programmer's Guide - MNIS

Synopsisvoid sui_dinfo_inc_refcnt (datai); sui_dinfo_t * datai;

Arguments

dataiPointer to dinfo structure.

File

sui_dinfo.c

Name

sui_dinfo_dec_refcnt — Decrease reference count of DINFO

Synopsisvoid sui_dinfo_dec_refcnt (datai); sui_dinfo_t * datai;

Arguments

dataiPointer to dinfo structure.

Description

If the reference count reaches zero, DINFO starts to be destroyed. The eventSUEV_COMMAND with command SUCM_DONE is sent to dinfo, next eventSUEV_FREE is emmited or direct free is called the SUEV_FREE is disabled.

File

sui_dinfo.c

Name

sui_create_dinfo — Creates new dynamic DINFO

Synopsissui_dinfo_t * sui_create_dinfo (adata, afdig, amin, amax, ainfo, rd,

Page 292: WP10 -D10.8 Programmer's Guide - MNIS

wr); void * adata;int afdig;long amin;long amax;long ainfo;sui_datai_rdfnc_t * rd;sui_datai_wrfnc_t *

wr;

Arguments

adataDINFO type specific pointer to the data

afdigNumber of fractional digits if the fixed decimal point format is used

aminThe minimal allowed value

amaxThe maximal allowed value

ainfoDINFO type specific pointer

rdPointer to the read processing function

wrPointer to the write processing function

Return Value

Pointer to newly created DINFO.

File

sui_dinfo.c

Name

sui_create_dinfo_int — Creates DINFO for signed integer or fixed point data

Synopsissui_dinfo_t * sui_create_dinfo_int (adata, aidxsize, asize); void * adata;long aidxsize;int asize;

Page 293: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

adataPointer to the signed char, short, int, long or fixed point data

aidxsizeAllowed range of indexes form 0 to aidxsize-1, if zero, then no check

asizeThe size of the integer type representation returned by sizeof

Return Value

Pointer to newly created DINFO.

File

sui_dinfo.c

Name

sui_create_dinfo_uint — Creates DINFO for unsigned integer or fixed point data

Synopsissui_dinfo_t * sui_create_dinfo_uint (adata, aidxsize, asize); void * adata;long aidxsize;int asize;

Arguments

adataPointer to the unsigned char, short, int, long or fixed point data

aidxsizeAllowed range of indexes form 0 to aidxsize-1, if zero, then no check

asizeThe size of the integer type representation returned by sizeof

Return Value

Pointer to newly created DINFO.

File

sui_dinfo.c

Page 294: WP10 -D10.8 Programmer's Guide - MNIS

Name

sui_rd_long — Reads long integer data from specified DINFO

Synopsisint sui_rd_long (datai, idx, buf); sui_dinfo_t * datai;long idx;long * buf;

Arguments

dataiPointer to the DIONFO

idxIndex of read data inside DINFO.

bufPointer to where the read value is stored

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo.c

Name

sui_wr_long — Writes long integer data to specifies DINFO

Synopsisint sui_wr_long (datai, idx, buf); sui_dinfo_t * datai;long idx;const long * buf;

Arguments

dataiPointer to the DIONFO

idxIndex of read data inside DINFO.

buf

Page 295: WP10 -D10.8 Programmer's Guide - MNIS

Pointer to the new data value

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo.c

Name

dinfo_scale_proxy — Creates value scale proxy DINFO

Synopsissui_dinfo_t * dinfo_scale_proxy (dfrom, ainfo, amultiply, adivide); sui_dinfo_t * dfrom;long ainfo;long amultiply;long adivide;

Arguments

dfromPointer to the underlying DINFO

ainfoThe local DINFO specific parameter

amultiplyMultiply factor

adivideDivide factor

Description

Creates scaling proxy DINFO. Read value is multiplied by amultiply factor andthen divided by adivide factor. The long integer overflow is not checked. If thefull checking is required use sui_lintrans_proxy instead which works withwider numbers representations and checks for all overflow cases.

Return Value

Pointer to newly created DINFO.

File

sui_dinfo.c

Page 296: WP10 -D10.8 Programmer's Guide - MNIS

Name

dinfo_simple_proxy — Creates simple proxy DINFO

Synopsissui_dinfo_t * dinfo_simple_proxy (dfrom, ainfo); sui_dinfo_t * dfrom;long ainfo;

Arguments

dfromPointer to the underlying DINFO

ainfoThe local DINFO specific parameter which specifies index value for callingof underlying DINFO

Return Value

Pointer to newly created DINFO.

File

sui_dinfo.c

Name

sui_dinfo_dbuff_create — Creates DINFO for ul_dbuff structure

Synopsissui_dinfo_t * sui_dinfo_dbuff_create (db, aidxsize); ul_dbuff_t *

db;

long aidxsize;

Arguments

dbPointer to the dbuff

aidxsizeAllowed range of indexes form 0 to aidxsize-1, if zero then no check

Returns

Pointer to newly created DINFO.

Page 297: WP10 -D10.8 Programmer's Guide - MNIS

File

sui_dinfo_dbuff.c

Name

sui_dinfo_dbuff_rd_dbuff — Reads ul_dbuff data from specified DINFO

Synopsisint sui_dinfo_dbuff_rd_dbuff (di, idx, dbuf); sui_dinfo_t * di;long idx;ul_dbuff_t * dbuf;

Arguments

diPointer to the DIONFO

idxIndex of read data inside DINFO.

dbufPointer to where the read value is stored

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo_dbuff.c

Name

sui_dinfo_dbuff_wr_dbuff — Writes ul_dbuff data to specifies DINFO

Synopsisint sui_dinfo_dbuff_wr_dbuff (di, idx, dbuf); sui_dinfo_t * di;long idx;const ul_dbuff_t *

dbuf;

Page 298: WP10 -D10.8 Programmer's Guide - MNIS

Arguments

diPointer to the DIONFO

idxIndex of read data inside DINFO.

dbufPointer to the dbuff

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo_dbuff.c

Name

sui_dinfo_dbuff_rd_long — Reads long integer data from specified dbuff DINFO

Synopsisint sui_dinfo_dbuff_rd_long (di, idx, buf); sui_dinfo_t * di;long idx;long * buf;

Arguments

diPointer to the DIONFO

idxIndex of read data inside DINFO.

bufPointer to the dbuff

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo_dbuff.c

Page 299: WP10 -D10.8 Programmer's Guide - MNIS

Name

sui_dinfo_dbuff_wr_long — Writes long integer data to specified dbuff DINFO

Synopsisint sui_dinfo_dbuff_wr_long (di, idx, buf); sui_dinfo_t * di;long idx;const long * buf;

Arguments

diPointer to the DIONFO

idxIndex of read data inside DINFO.

bufPointer to the dbuff

Return Value

Operation result code, SUDI_DATA_OK in the case of success.

File

sui_dinfo_dbuff.c

Name

sui_dtree_lookup — Find dinfo in the named dinfo database

Synopsisint sui_dtree_lookup ( from_dir, path, found_dir, datai); sui_dtree_dir_t * from_dir;const char * path;sui_dtree_dir_t ** found_dir;sui_dinfo_t ** datai;

Arguments

from_dirthe directory to start from

path

Page 300: WP10 -D10.8 Programmer's Guide - MNIS

path from directory to dinfo or directoryfound_dir

the optional pointer to space that would hold pointer to directory of founddinfo

dataioptional pointer to store the found dinfo

Return Value

SUI_DTREE_FOUND, SUI_DTREE_DIR, SUI_DTREE_NOPATH,SUI_DTREE_ERROR

File

sui_dtree.c

Name

sui_dtree_mem_lookup — Find dinfo in the named dinfo database

Synopsisint sui_dtree_mem_lookup ( from_dir, path, consumed, found_dir, datai); sui_dtree_dir_t * from_dir;const char * path;int * consumed;sui_dtree_dir_t ** found_dir;sui_dinfo_t ** datai;

Arguments

from_dirthe directory to start from

pathpath from directory to dinfo or directory

consumedpointer to location for numeber of consumed characters from path

found_dirthe optional pointer to space that would hold pointer to directory of founddinfo

dataioptional pointer to store the found dinfo

Page 301: WP10 -D10.8 Programmer's Guide - MNIS

Return Value

SUI_DTREE_FOUND, SUI_DTREE_DIR, SUI_DTREE_NOPATH,SUI_DTREE_ERROR

File

sui_dtreemem.c

Name

struct sui_dtree_memdir_t — Ancestor of sui_dtree_dir_t which containingsui_dtree_memnode_t GAVL list .

Synopsisstruct sui_dtree_memdir_t { sui_dtree_dir_t dir; gavl_cust_root_field_t name_root;};

Members

dirbase struct (Container_of technology). Containing dir needs it.

name_rootGAVL with children of type &sui_dtree_memnode_t

Header

sui_dtreemem.h

Name

struct sui_dtree_memnode_t — structure representing single node in memtree.

Synopsisstruct sui_dtree_memnode_t { char * name; int node_type; gavl_node_t name_node; union ptr; void * dll_handle;};

Members

namestructure neccessary for storing node in GAVL tree, is NULL for subindicies

node_type

Page 302: WP10 -D10.8 Programmer's Guide - MNIS

type of node contens (dir or dinfo)name_node

the structure can be stored in GAVL tree thanks to that fieldptr

pointer to dinfo or directory that this node contains.dll_handle

if memnode is one imported from DLL, DLLs handle is stored here. (else itis 0)

Description

Node can contain dinfo or directory (&sui_dtree_dir_t).

Header

sui_dtreemem.h.h

Name

struct sui_event — Common suitk event structure

Synopsisstruct sui_event { unsigned short what;};

Members

whatCode of event.(See 'event_code' enum with 'SUEV_' prefix)

File

sui_base.h

Name

enum event_code — Code of SUITK events ['SUEV_' prefix]

Synopsisenum event_code { SUEV_MDOWN, SUEV_MUP, SUEV_MMOVE, SUEV_MAUTO, SUEV_KDOWN, SUEV_KUP, SUEV_DRAW, SUEV_REDRAW,

Page 303: WP10 -D10.8 Programmer's Guide - MNIS

SUEV_COMMAND, SUEV_BROADCAST, SUEV_SIGNAL, SUEV_GLOBAL, SUEV_FREE, SUEV_NOTHING, SUEV_MOUSE, SUEV_KEYBOARD, SUEV_MESSAGE, SUEV_DEFMASK, SUEV_GRPMASK};

Constants

SUEV_MDOWNMouse button is down.

SUEV_MUPMouse button is up.

SUEV_MMOVEMouse is in move.

SUEV_MAUTOSUEV_KDOWN

Key is down.SUEV_KUP

Key is up.SUEV_DRAW

Draw widget.SUEV_REDRAW

Redraw widget.SUEV_COMMAND

Command event.SUEV_BROADCAST

Bradcast event.SUEV_SIGNAL

?SUEV_GLOBAL

?SUEV_FREE

?SUEV_NOTHING

?SUEV_MOUSE

?SUEV_KEYBOARD

?SUEV_MESSAGE

?SUEV_DEFMASK

?

Page 304: WP10 -D10.8 Programmer's Guide - MNIS

SUEV_GRPMASK?

File

sui_base.h

Name

enum command_event — Command codes for command event ['SUCM_' prefix]

Synopsisenum command_event { SUCM_VALID, SUCM_QUIT, SUCM_ERROR, SUCM_MENU, SUCM_CLOSE, SUCM_ZOOM, SUCM_RESIZE, SUCM_NEXT, SUCM_PREV, SUCM_HELP, SUCM_OK, SUCM_CANCEL, SUCM_YES, SUCM_NO, SUCM_DEFAULT, SUCM_FOCUSASK, SUCM_FOCUSSET, SUCM_FOCUSREL, SUCM_INIT, SUCM_DONE, SUCM_NEWDISPLAY, SUCM_DISPNUMB, SUCM_CHANGE_STBAR, SUCM_NEXT_GROUP, SUCM_PREV_GROUP, SUCM_EVC_LINK_TO};

Constants

SUCM_VALIDVALID command event.

SUCM_QUITQUIT command event.

SUCM_ERRORERROR command event.

SUCM_MENUMENU command event. Open, select, close, ... menu.

Page 305: WP10 -D10.8 Programmer's Guide - MNIS

SUCM_CLOSECLOSE command event.

SUCM_ZOOMZOOM command event.

SUCM_RESIZERESIZE command event.

SUCM_NEXTNEXT command event. Mainly for change widget focus by pressing TABkey.

SUCM_PREVPREV command event. Mainly for change widget focus by pressingSHIFT+TAB key.

SUCM_HELPHELP command event.

SUCM_OKOK button pressed.

SUCM_CANCELCANCEL button pressed.

SUCM_YESYES button pressed.

SUCM_NONO button pressed.

SUCM_DEFAULTDEFAULT button pressed.

SUCM_FOCUSASKWhich widget has focus ?

SUCM_FOCUSSETSet focus to the widget.

SUCM_FOCUSRELRelease focus from the widget.

SUCM_INITInitialize widget.

SUCM_DONEDone widget - decrement reference counter, deallocate widget data.

SUCM_NEWDISPLAYCreate new screen from pointer to screen.

SUCM_DISPNUMBCreate new screen from number to screen.

SUCM_CHANGE_STBARStatus bar is changed.

SUCM_NEXT_GROUPChange focus between groups (like as ALT+TAB in Windows).

SUCM_PREV_GROUPChange focus between groups.

SUCM_EVC_LINK_TOOnly Pavel Pisa knows :))

Page 306: WP10 -D10.8 Programmer's Guide - MNIS

File

sui_base.h