1 Aralık 2014 Pazartesi

cpuMonitorLib

Bu kütüphane ile bölümlemelerin ne kadar işlemci kullandıkları görülebilir.

PuTTy üzerinde
[coreOS]-> yazısı görününce

cpuMonitorStart ile ölçüm başlatılır.
cpuMonitorReport ile rapor PuTTy ile görülür
cpumonitorStop ile ölçüm durdurulur

Eğer coreOS cpuMonitorLib bileşenini içermiyorsa ekranda
No symbol "cpuMonitorStart" in protection domain "coreOS" yazısı çıkar.

13 Ekim 2014 Pazartesi

ARINC 653 Bölümlenmeler Arası İletişim

Not : VxWorks 563 ve Portlar yazısına da bakabilirsiniz.

Giriş
ARINC 653 bir işletim sistemi API'si. Aynen POSIX'te olduğu gibi metod imzalarını tanımlıyor. Metodların gerçekleştirilmesi işletim sistemi üreticilerine bırakılmış.

Nasıl ki POSIX'te Inter Process Communication yöntemleri varsa, ARINC 653'te Inter Partition Communication - yani Bölümlenmeler Arası İletişim - yöntemleri tanımlıyor.

Bölümlenmeler Arası (Interpartition) İletişim Yapıları
Bu iletişim yapılarını genel ismi "port". Queeing Port  ve Sampling Port olarak iki türü var.
İki veya daha fazla portu birbirine bağlayan yapıya ise Channel deniliyor.

Broadcast, Multicast and Unicast Messages
This standard provides support for broadcast, multicast and unicast messages. A broadcast message is sent from a single source to all destinations. A multicast message is sent from a single source to more than one destination. A unicast message is sent from a single source to a single destination. For queuing port ony unicast messages are required.

Overflow
Application software is responsible for handling overflow when the queuing port is full.

Queuing Port
Bir çeşit FIFO kuyruk. Kuyruk dolarsa yazan taraf bloke olabiliyor. Bir port ile çalışmak için toplam 5 tane metod var:
  1. CREATE_QUEUING_PORT
  2. SEND_QUEUING_MESSAGE
  3. RECEIVE_QUEUING_MESSAGE
  4. GET_QUEUING_PORT_ID
  5. GET_QUEUING_PORT_STATUS
CREATE_QUEUING_PORT ile ismi olan bir port yaratılır. Bu metod isme karşılık bir port ID'si döner. Geri kalan tüm SEND, RECEIVE, GET metodlarında bu port ID'si kullanılır.

CREATE_QUEUING_PORT metodu
Yeni bir port yaratır. Metodun imzası şöyledir.

extern void CREATE_QUEUING_PORT (
   /*in */ QUEUING_PORT_NAME_TYPE    QUEUING_PORT_NAME, //Portun ismi
   /*in */ MESSAGE_SIZE_TYPE         MAX_MESSAGE_SIZE,  //Bir mesajın büyüklüğü
   /*in */ MESSAGE_RANGE_TYPE        MAX_NB_MESSAGE,    //Toplam mesaj sayısı
   /*in */ PORT_DIRECTION_TYPE       PORT_DIRECTION,    //Source veya Destination
   /*in */ QUEUING_DISCIPLINE_TYPE   QUEUING_DISCIPLINE,//FIFO veya PRIORITY
   /*out*/ QUEUING_PORT_ID_TYPE      *QUEUING_PORT_ID,  //Port ID'si
   /*out*/ RETURN_CODE_TYPE          *RETURN_CODE       //Çağrı sonucu
);

QUEUING_DISCIPLINE parametresinin varlığı aynı porta partition içindeki farklı thread'lerin yazabileceğini gösterir. Kuyruk doluysa thread bekletilir. İlk yer açıldığında beklemekte olan hangi threadin devreye gireceğini bu parametre belirler.

Dikkat edilmesi gereken nokta portlara yazılabilecek mesaj sayısının üst sınırının olması. Yani portları sınırsız kuyruk gibi düşünmek doğru değil. Mesaj sayısının üst sınırı
#define SYSTEM_LIMIT_NUMBER_OF_MESSAGES        512    /* module scope */
ile tanımlı.Dolayısıyla MAX_NB_MESSAGE, yukarıdaki sabiti geçemez.


SEND_QUEUING_MESSAGE metodu
Kuyruğa yeni bir eleman ekler. Metodun imzası şöyledir. Bu metodu kullanabilmek için CREATE_PORT metodunun QUEUING_DISCIPLINE = SOURCE olarak çağrılmış olması gerekir.

extern void SEND_QUEUING_MESSAGE (
      /*in */ QUEUING_PORT_ID_TYPE      QUEUING_PORT_ID,
      /*in */ MESSAGE_ADDR_TYPE         MESSAGE_ADDR,       /* by reference */
      /*in */ MESSAGE_SIZE_TYPE         LENGTH,
      /*in */ SYSTEM_TIME_TYPE          TIME_OUT,
      /*out*/ RETURN_CODE_TYPE          *RETURN_CODE);

Bu metodun en önemli parametresi TIME_OUT. Metodun blocking veya non-blocking olmasına bu parametre ile karar veririz. TIME_OUT parametresi 0 (sıfır) ise metod yazma işlemini gerçekleştiremezse hemen döner. Bu durumda sonuç NOT_AVAILABLE değerini alır. 0'dan büyük bir değer ise belirtilen süre kadar kuyrukta yer açılmasını bekler. Belirtilen süreden dana önce yer açılırsa sonuç NO_ERROR değeri ile döner. Eğer yer açılmazsa sonuç TIMED_OUT değerini alır.

Örnek'te sonsuza kadar kuyrukta yer açılması bekleniyor.
QUEUING_PORT_ID_TYPE fd;                     //Port ID
char msg[1025] = ... ;                                        //Populate array
MESSAGE_SIZE_TYPE length = sizof(msg);//Length of msg
RETURN_CODE_TYPE rc;                            //Return code
SEND_QUEUING_MESSAGE (fd,
                        (MESSAGE_ADDR_TYPE)msg,//byte array
                        length,
                        INFINITE_TIME_VALUE,
                        &rc
                     );

Tipik ARINC 653 uygulamalarında port ile bir timer beraber kullanılır. Timer expire olunca periyodik göndermesi gereken mesajlar porta yazılır.

Yine tipil ARINC 653 uygulamalarında port yapısı bir channel yapısına bağlı olduğu için aynı port numaralarını kullanan farklı uygulamalar kuyruğa yazabilirler.

Şekilde aynı port numaralarını kullanan farklı uygulamaların kuyruğa yazıp, okuyabildikleri görülebilir.

RECEIVE_QUEUING_MESSAGE metodu

Bu metodu kullanabilmek için CREATE_PORT metodunun QUEUING_DISCIPLINE = DESTINATION olarak çağrılmış olması gerekir.

Tipik bir ARINC 653 uygulaması portları saklanan tüm mesajları bitirinceye kadar okur.

while (true) {
  if (ReadPort (...)) {
     ProcessPort (...);
  } else  {
    break;
  }
}

GET_QUEUING_PORT_ID metodu
Açıklama yaz.

GET_QUEUING_PORT_STATUS metodu
Açıklama yaz.

Sampling Port
Tek bir eleman alıyor. Her güncelleme işlemi bir önceki bilginin üzerine yazar. Okuyan taraf her zaman en son bilgiyi çekiyor.
Bir port ile çalışmak için toplam 5 tane metod var:

  1. CREATE_SAMPLING_PORT
  2. WRITE_SAMPLING_MESSAGE
  3. READ_SAMPLING_MESSAGE
  4. GET_SAMPLING_PORT_ID
  5. GET_SAMPLING_PORT_STATUS


CREATE_SAMPLING_PORT metodu
Yeni bir port yaratır. Metodun imzası şöyledir.

extern void CREATE_SAMPLING_PORT ( 
  /*in */ SAMPLING_PORT_NAME_TYPE    SAMPLING_PORT_NAME, //Portun ismi
  /*in */ MESSAGE_SIZE_TYPE          MAX_MESSAGE_SIZE,   //Elemanın büyüklüğü
  /*in */ PORT_DIRECTION_TYPE        PORT_DIRECTION,     //Source veya Destination
  /*in */ SYSTEM_TIME_TYPE           REFRESH_PERIOD,     //Yenilenme süresi (san.)
  /*out*/ SAMPLING_PORT_ID_TYPE      *SAMPLING_PORT_ID,  //Port ID'si
  /*out*/ RETURN_CODE_TYPE           *RETURN_CODE        //Çağrı sonucu
); 

Metod CREATE_QUEUING_PORT metoduna çok benzer. Ancak bu sefer porta kaç tane mesaj yazılacağı belirtmeyiz çünkü bu port türünde sadece tek bir eleman bulunur. Onun yerine bu tek elemanın ne kadar sıklıkta yenilenmesi gerektiğini belirtiriz.

WRITE_SAMPLING_MESSAGE metodu
Porttaki tek elemanı günceller. Kaynak port (source) için Refresh Period değeri anlamsızdır.

READ_SAMPLING_MESSAGE metodu
Metodun imzası aşağıda.
extern void READ_SAMPLING_MESSAGE ( 
       /*in */ SAMPLING_PORT_ID_TYPE      SAMPLING_PORT_ID, 
       /*out*/ MESSAGE_ADDR_TYPE          MESSAGE_ADDR, 
       /*out*/ MESSAGE_SIZE_TYPE          *LENGTH, 
       /*out*/ VALIDITY_TYPE              *VALIDITY, 
       /*out*/ RETURN_CODE_TYPE           *RETURN_CODE ); 

Sampling port'a "Refresh Period" değeri atanır. Bu değer saniye cinsindendir, okunan verinin güncel olup olmadığını belirtir. Örneğin 100 milisaniye vermek için 0.1 yazılır. Eğer hiç süresi dolmayan bir port yaratılmak istenirse, -1 değeri verilir.

Sampling Portu okuyan kod kabaca şöyle çalışır.

UINT64 curTime = sysTimestamp64Get();
UINT64 diffTime = sysTimestamp64DiffToNSec (curTime,msgTimeStamp,0ull);
if (TA_IS_INFINITE (sportId->refreshPeriod) ||
    TA_LT (diffTime,sportId->refreshPeriod)      ||
    TA_EQ (diffTime,sportId->refreshPeriod) {
  *VALIDITY = VALID;
}else {
   *VALIDITY =INVALID;
}

GET_SAMPLING_PORT_ID metodu
Açıklama yaz.

GET_SAMPLING_PORT_STATUS metodu
Açıklama yaz.


Okuma İşlemini Gerçekleştiren Uygulananın Yavaş Kaldığı Nasıl Anlaşılır?
Queuing Port'u dolduran uygulama kuyruk doldu hatası alırsa boşaltan uygulamanın yeterince hızlı olmadığını anlarız. Sampling Port kullanırken ise port'u okuyan uygulama DEADLINE  MISS hatası alırsa yeterince hızlı olmadığını anlayabiliriz.


9 Ekim 2014 Perşembe

VxWorks 653 ve Portlar

Giriş
Not : ARINC 653 ve Bölümlemeler Arası İletişim yazısı standardı açıklıyor.

Bölümlemeler arasında iletişim için kullanılan en temel yöntem portlar. İki çeşit port var. Bunlar Queuing Port ve Sampling Port.
APEX partitions within VxWorks 653 module communicate with each other by messages, ports and channels. A message can be sent from one source to one or more destination ports. Processes read from these destination ports.

Messages
Bölünemez bellek alanı olarak tanımlı.
APEX messages are contiguous blocks of data
Mesajlar directed veya broadcast olarak tanımlanıyorlar. Burada ARINC 653 standardından daha farklı bir terminoloji kullanılıyor. Standartta Broadcast, Multicast, Unicast mesajlar tanımlı. VxWorks unicast yerine directed kelimesini tercih etmiş.
A message sent to one destination port is called a directed message. A message sent to multiple destination ports is called a broadcast message.
Port Protocols
Arınc 653'te port protocol tanımlı değil ancak VxWorks 653 şu özellikleri sağlıyor. XML içinde Protocol tag'i tanımlı olmalı ve Source Port SENDER_BLOCK veya RECEIVER_DISCARD protokollerinden birini seçmek zorunda. Destination Port ise NOT_APPLICABLE değerini kullanmak zorunda. Aksi halde XML derleyicisi hata verir.

SENDER_BLOCK
Eğer destination portlardan birisi doluysa, göndereni bekletir. Bu protokolün dezavantajı aşağıda belirtilmiş.
The main drawback is that it introduces coupling between partitions. A non-responsive receiving partition blocks the entire channel, affecting the normal behavior of other receiving partitions.

RECEIVER_DISCARD
Eğer destination portlardan birisi doluysa, bu port pas geçilir ve mesaj boş olan diğer portlara yazılır.

Queuing port XML Örneği
Örnek yaz.

Sampling Port XML Örneği
QueuingPort ile ortak olan tag isimleri Direction, MessageSize ve Name. RefreshRate saniye cinsindendir. Örneğin aşağıdaki 0.050 50 milisaniye anlamına gelir.

<Applications>
    <ApplicationDescription Name = "Partition">
        <MemorySize..../>
        <Ports>
            <SamplingPort
                Direction = "Source"
                MessageSize = "90"
                Name = "OutputPort2"
                RefreshRate = "0.050"/>
        <Ports>
     </ApplicationDescription>
</Applications>

Port ve Connection Bağlantısı
Port'lar için Connection'lar aşağıdaki gibi tanımlanıyor. PortNameRef  partition tagleri içinde tanımlı bir porta atıfta bulunmalı. bu port QueuingPort veya Sampling port ile tanımlanmalı.

<Connections>
 <Channel Id="1">
  <Source PartitionNameRef="Partition1" PortNameRef="To_Part2"/>
  <Destination PartitionNameRef="Partition2" PortNameRef="From_Part1"/>
 </Channel>
</Connections>

Pseudo Partition
Pseudo Partition şöyle açıklanıyor :
A partition that is external to the module. 
Genellikle farklı modul'ler arası ileitşim için kullanılır.

<PseudoPartition Name ="pseudoPartition" Id ="4" Type = "IO_PARTITION">
    <PseudoPartitionDescription>
        <Ports>
            <QueuingPort
                  Atrribute="PSEUDO_PORT"
                  Name = "Output"
                  QueueLength="5"
                  MessageSize="100"
                  Direction = "SOURCE"
                  Protocol="SENDER_BLOCK"
                  DriverName="pseudoQPort" />
        <Ports>
    </PseudoPartitionDescription>
 </PseudoPartition>

25 Ağustos 2014 Pazartesi

Makefile Kullanma

Makefile
Projeyi yarattıktan sonra Eclipse tabanlı WorkBench'i kullanılabileceği gibi, istenirse komut satırından make yapabilmek te mümkün.

makefile kullanabilmek için workbench'in kurulduğu dizindeki wrenv komutunu çalıştırmak gerekir. Bu komut Windows ve Unix için farklı dosyalar. Bu komut ile kabuktaki (shell) ortam değişkenleri (environment variables) atanıyor. Böylece mutlak dizinleri make dosyasında kullanmak zorunda kalmayız.
Atanan değişkenler şunlar
set PATH=
set WIND_PREFERRED_PACKAGES=
set WIND_HOME=
set WIND_HOST_TYPE=
set WIND_GNU_PATH=
set WIND_TOOLCHAINS=
set WIND_DOCS=
set WIND_TOOLS=
set FLEXLM_NO_CKOUT_INSTALL_LIC=
set LD_LIBRARY_PATH=
set WRSD_LICENSE_FILE=
set WIND_DFW_PATH=
set WIND_JRE_HOME=
set WIND_WRUB_PATH=
set WIND_WRSV_PATH=
set WIND_SAMPLES=
set WIND_USERMODE_AGENT=
set WIND_EXTENSIONS=
set WIND_SCOPE_TOOLS_BASE=
set WIND_RSS_CHANNEL=
set WIND_INSTALLER_HOME=
set WIND_WB_SCRIPTS=
set WIND_ANALYSIS_TARGET_SCRIPT_BASE=
set WIND_INITRO=
set WIND_FOUNDATION_PATH=
set WIND_UTILITIES=
set WIND_TCL_PATH=
set WIND_TCLLIBPATH=
set INCLUDE=
set LIB=

Örnek kullanım şekli.
wrenv -p vxworks653.x.y.z
wrenv komutu kendi shell'ini çalıştırıyor. Eğer sadece ortam değişkenlerini almak ve yeni bir shell açmadan kullanmak istersek aşağıdaki komut ile wrenv'in atadığı değişkenleri başka bir dosyaya almak mümkün.
wrenv -p vxworks653-2.3.0.1 -o print_env -f bat > env.bat
Sadece değişkenleri görmek için ise
wrenv -p vxworks653-2.3.0.1 -o print_env 
komutu çalıştırılmalı.

make dosyamıza VxWorks kurulumunda gelen Makefile.vars dosyasınıa dahil etmek gerekli. Bu dosya işlemci mimarisini tanımlıyor. Örneğin PPC604 gibi. Seçilen işlemciye göre projeyi derlerken kullanılacak işlemci ve ortama mahsus ayarları içeren diğer dosyalar dahil ediliyor. Yukarıdaki örnek için Makefile.vars.PPC604 dahil edilir. Makefile.vars.PPC604 dosyasında TOOLARCH = ppc olarak tanımlı. Dolayısıyla CC = ccppc değerini alır.

Derleyiciler kurulumda gnu\x.y.z-vxworks653\x86-win32\bin dizininde. İşlemciye göre derleyiciler mevcut. PowerPC için ccppc.exe, c++ppc.exe, cppppx.exe, g++ppc.exe gibi derleyiciler mevcut. Aralarındaki farkı bilmiyorum ancak makefile yukarıda da anlattığım gibi ccppc.exe'yi kullanıyor. ccppc "GNU C Compiler for PowerPC" imiş. ccppc.exe Wind River firması tarafından değiştirilmiş gcc tabanlı bir derleyici. Normal gcc sürümünü oldukça gerilden takip ediyor. Örneğin gcc sürümü 4.8 iken, firma 3.3.2 tabanlı bir derleyici sunuyor. Dosya uzantısı .c veya .cpp olmayan ya da tanıyamadığı dosyalar içinse g++ppc'yi kullanmaya çalışıyor. (Bu cümleyi daha sonra açıkla)

19 Ağustos 2014 Salı

VxWorks 653 ve Partition OS Bileşenleri

Bazı PartitionOS Bileşenleri
Routines must be exported from partition OS to user tasks using the  system XML-language description files in the "Interface" section.

PartitionOS esnek bir işletim sistemi olduğu için, uygulamalar sunacağımız kabiliyetleri seçebiliyoruz. Üzerinden düşünülerek karar verilmesi gereken en önemli bileşenler vThread (cert olup olmadığı), APEX (minimal olup olmadığı) , C++ (extended olup olmadığı).

Havacılık uygulamaları kendiliğinden bazı kısıtlamalar getirdiği için vThread (cert), APEX, C++ (minimal) seçileceği belli, ancak diğer alanlarda seçim yapabilme imkanı var.

Bileşenleri Eklemek

Bazı bileşenler XML dosyasından eklenirken, bazılarını linklemek gerekiyor. Yani tutarsız bir yol izlenmiş. Herşey XML ile yapılsaydı daha iyi olurdu.

Değiştirilmesi gereken XML dosyası PartitionOS projesindeki PartitionİsmiOS.xml dosyası.


Örnek bir PartitionOS XML dosyası aşağıda.

<Shared_Library_API xmlns="http://www.windriver.com/vxWorks653/SharedLibraryAPI"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    Name="vThreads"
    >

    <Interface>
        <Version Name="Cert"/>
        <xi:include href="$(WIND_BASE)/target/vThreads/config/comps/xml/apex.xml" />
        <xi:include href="$(WIND_BASE)/target/vThreads/config/comps/xml/vthreads_cert.xml" />
        <xi:include href="$(WIND_BASE)/target/vThreads/config/comps/xml/vthreads_shell.xml" />
   
       <!--Belli bir XML subsetinde olmayan routine'ler böyle export edilebilir. -->
        <Interface_Subset>
                 <Routine Name="sfsprintf"/>
        </Interface_Subset>
    </Interface>
</Shared_Library_API>

Bazı projelerde <Interface_Subset> ile başlayan tag'ler yeni bir XML içine taşınıyor. Böylece PartitionOS.xml dosyası daha rahat okunabilir hale geliyor.

vThread Bileşeni
Bu bileşen, hem işletim sistemi tarafından sunulacak API'leri hem de C runtime API'lerini sunar.

vThread.xml
Daha geniş bir C API'si sunuyor.

vThread_cert.xml
suggested CERT POS API anlamına geliyor. Daha kısıtlı C API'si sunuyor. vThreads dizinindeki libc için kullanılan make dosyasında şöyle bir satır var.
ifdef CERT
 EXCLUDE_SUBDIRS = stdio
Yani C runtime kütüphanesinden stdio başlığı altına düşen fread, fwrite gibi I/O ve dosya sistemini ilgilendiren metodlar cert sürümüne dahil edilmiyor.


Kendi uygulamamız içinde, Partition OS için vThreadsComponent.o ile link etmek gerekiyor.
vthreads_cert.xml örneği aşağıda.
<Interface_Subset xmlns="http://www.windriver.com/vxWorks653/SharedLibraryAPI">
  <Routine Name ="errnoGet"/>
 .
 .
 .
</Interface_Subset>

ARINC 653 APEX Bileşeni
Uygulama ile en çok kullanılan standartlar ARINC 653 APEX ya da POSIX standartları.

VxWorks APEX Supplement 2 Part 1 (Mandatory Services) başlığı altındaki hizmetleri destekliyor.

Supplement 2 Part 2 (Optional Services) başlığı altındaki hizmetleri 2013 yılı itibariyle desteklemiyor.



POSIX Bileşeni
Aynı APEX bileşeni gibi XML ile kullanılıyor.

C++ Bileşeni
Aşağıdaki cümleler önemli.

VxWorks 653 support applications written in C++. However, the C++ support components must be added separately to each application, by adding the C++ components to the application's build.

C++ iki farklı sürüm ile geliyor. İlki "full c++" diğer ise "cert c++" . cert c++ havacılık uygulamalarında kullanılan daha kısıtlı bir sürüm. Aşağıdaki açıklama cert c++ sürümünün farkını ortaya koyuyor.
C++ Cert subset does not support the following C++ features.
* C++ standard library
* Exception handling (catch and throw)
* Pure virtual functions (virtual functions are supported) - bu ne anlama geliyor bilmiyorum
* RTTI
* STL 
Dikkatimi çeken önemli bir nokta proje cert bile olsa template kullanan kodların başarılı bir şekilde derlenmesi oldu.

vThreadsCplusComponent.o : Provides basic C++ support and is suitable for inclusion in cert applications.
vThreadsCplusLibraryComponent.o : Provides extended C++ support but can not be included in cert applications.

C++ bileşeni nedense XML ayarı ile eklenmiyor. Bu bileşenlerden birini Libraries sekmesinde link etmek gerekir. Uygulamamızı link ederken hangi C++ bileşenini kullanacağımızı vermemiz lazım.


Yukarıdaki her iki kütüphane de aslında aşağıda açıklaması olan cpluslib.o'yu kullanıyor. Dolayısıyla yukarıdaki iki kütüphaneyi kullanmadan sadece cpluslib.o'yu kullanmak bile yeterli olabilir.

cpluslib.o: Bu kütüphanenin linki burada. Açıklaması ise "basic run-time support for C++"

Örneğin operator new vThreads/lib/objPPC604gnucert veya vThreads/lib/objPPC604gnuvx altındaki newop.o, newop2.o gibi object dosyaları altında.

Bir diğer önemli nokta ise, VxWorks 653 kullanırken, C ve C++ dillerini beraber kullanmak gerekebilir. Bu durumda şu noktalara dikkat etmek lazım.

C'den C++ dosyasındaki bir metodunu çağırırken metodunun name mangling'e (name decoration) uğramaması için extern "C" 'yi kullanmak gerekir. Örnek
extern "C" {
   void foo();
}




Partition OS Nedir

PartitionOS Nedir
PartitionOS bir shared library'dir.
To conserve resources, PartitionOSs are located in a special kind of shared library called a system shared library.
PartitionOS Build System
The PartitionOS build process produces a system module (.sm) file for the shared library. This is an ELF file that can be included in a sytem image build.

PartitionOS Planning
Partition OS bir çok bileşeni içerebildiği için planlanması gerekir.
There are a number of components that can be added to a partition OS to provide added functionality. 

Bazı bileşenler binary (Makefile için ekleniyorlar) ve build sırasında linkleniyorlar. Bazı bileşenler ise XML ile tanımlı. Konuyla ilgili olarak VxWorks 653 Partition OS Bileşenleri başlıklı yazıya göz atabilirsiniz.





17 Temmuz 2014 Perşembe

Process İçinden Hata Göndermek

Partition İçinden Hata Göndermek
Aşağıda uygulamamız içinde hata mesajı gönder örneği var.

RETURN_CODE_TYPE retCode;
char message [HM_MAX_SIZE_EVENT_MSG];
int msgLen = sprintf (&message[0],"STOP:\n");
RAISE_APPLICATION_ERROR (APPLICATION_ERROR,message,msgLen,&retCode);

VERIFY Macrosu
Bazı frameworklerde bulunan VERIFY macrosuna benzer bir metod yazmak istersek aşağıdaki gibi yapabiliriz. Bu metod hatalı bölünmeyi durdurur ve debug edilmesine imkan tanır.

#define VERIFY(msg) _VERIFY(msg ## __FILE__)

extern "C" void _VERIFY (const char* msg) {
  int msgSize = strlen (msg);
  RETURN_CODE_TYPE retCode;
  RAISE_APPLICATION_ERROR (APPLICATION_ERROR,msg,msgSize,&retCode);
  int taskId = taskIdSelf ();
  taskSuspend (taskId);


}

22 Haziran 2014 Pazar

VxWorks 653 ve BlackBox

Giriş
Blackbox VxWorks dokümanlarında şöyle tanımlanmış.

Pre-determined memory configuration is achieved using black boxes. A black box is a section of memory set aside for a component of the system (core OS, shared library, application, partition or shared region)

Config Record Application BlackBox Nedir?
BlackBox "VxWorks 653 Integration Project" tipi projelerde, Partition'a ne kadar hafıza ayrılma gerektiği belirtir.

Nasıl Tanımlarız?
"Application" tipindeki Partition projemize sağ tıklarız ve (örneğin projemizin ismi Partition1 olsun) Properties menüsünü seçeriz. Açılan kutudan aşağıdaki şekilde gösterildiği gibi "Build Macros" sekmesine geliriz ve BlackBox alanına, ConfigRecord projesinde bu partition için tanımları içeren XML dosyasındaki Application tag'i içindeki Name değerini gireriz (BSPİsmi_default.xml dosyası örneğin wrSbc8641d_default.xml gibi)


XML'i gösteren bir başka belge burada.

ConfigRecord projesinin görünüşü mevcut.

BSP XML İçinde Yapılan Ayarlar

Blackbox ve Elf Dosyası Formatı
Üretilen elf dosyasının bazı ayarları XML ile yapılablir.

ELF Formatı Nedir?
VxWorks ile derlenen yazılım ELF formatında oluyor. Bu formattaki bazı segmentlerin isimler ve işlevleri aşağıda. Daha detay bilgi için C Programlarının hafıza yerleşimi başlıklı yazıya göz atabilirsiniz.

Bazen link esnasında section .rodata overlaps section .text gibi hata mesajları alabiliriz. Bu mesaj tanımladığımız .text alanının küçük geldiğini ve .rodata alanına taştığını ifade ediyor. .text için ayrılmış alanı artırmak lazım. Aşağıdaki Gcc Exception alanı başlığında bir tanımlama örneği var.

Böylece partition için elf dosyasında ne kadar yer ayrılması gerektiğini belirtmiş oluruz.
Bir başka örnek:
<MemorySize
    MemorySizeHeap="0x100000"
    MemorySizeBss="0x80000"
    MemorySizeText="0x100000"
    MemorySizeData="0x100000"
    MemorySizeRoData="0x20000"
    MemorySizePersistentData="0x10000"
    MemorySizePersistentBss="0x10000">
    <AdditionalSection Name=".gcc_except_table" Size="0x10000" Type="DATA"/>
</MemorySize>

Gcc Exception Alanı

Buradaki örnekte GCC ile C++ kullanılırken exception alanı için aşağıdaki kodu eklemek gerektiği görülüyor.

Buradaki soruda da C++ kodu kullanan ELF dosyaları için bu alanın gerekli olduğu belirtilmiş ancak neden gerekli olduğunu anlayamadım, çünkü VxWorsk 653 ile exception kullanılmadığını sanıyordum.

Shared IO Alanı

<CoreOSDescription>
  <KernelConfiguration ... />
  <MemorySize ... />
  <HardwareConfiguration>
    <PhysicalMemory .../>
    <kernelIO .../>
    <SharedIO PoolName="MyRegion" Size="0x00020000" Base_Address="0x60500000"/>
  </HardwareConfiguration>
  <Extensions />
</CoreOSDescription>

Config Record İçinde Yapılan Ayarlar
Heap Nedir?
Uygulama heap yetmezse new, malloc ile bellek ayıramaz ve açılmaz. Heap aşağıdaki XML ile ayarlanır.

<Partition Name =".." Id="..">
  <PartitionDescription>
    <Application NameRef=".."/>
    <SharedLibraryRegion NameRef=".."/>
    <Settings
      RequiredMemorySize ="0x200000" //Heap
      ...
      numStackGuardPages="0xffffffff"
  </PartitionDescription>
</Partition>

Shared Data Region Nedir?
VxWorks 653 introduces two types of shared data regions: the "shared data" to share memory between partitions and "shared I/O" to map hardware resources.

Örnek:

<SharedDataRegions>
   <SharedData Name="MyRegion"><!--BSP XML'deki isim ile aynı olmalı -->
   <SharedIODescription VirtualAddress="0" CachePolicy="IO" SystemAccess="READ_WRITE"/>
  </SharedData>
</SharedDataRegions>


Fault Tolerant Software

Fault Tolerant Software

Kavramlar
Patterns for Fault Tolerant Software kitabında Fault Tolerance'ı açıklamak için 3 kavram kullanılmış. Bunlar birbirleri ile ilintili.
Fault (Hata) -> Error (Türkçesi Nedir ? Yanlış?)-> Failure (Başarısızlık)
Kitapta verilen örneklerden birinde fatura hesaplarken yanlış fatura çıkması bir Failure, başarısızlığa sebep ise hatalı CDR gelmesi (Fault) ve hatalı CDR'ın hesaba geçirilmesi (Error) olarak tanımlanmış.Örneğin metni aşağıda.

A misrouted telephone call is an example of a failure. Telephone system requirements specify that calls should be delivered to the correct recipient. When a faulty system prevents them from being delivered correctly, the system has failed. In this case the fault might have been an incorrect call routing data being stored in the system. The error occurs when the incorrect data is accessed and an incorrect network path is computed with that incorrect data.

The preparation of an incorrect bill for service is another example of a failure.The system requirements specify that the customer will be accurately charged for service received. A faulty identifi cation received in a message by a billing system can result in the charges being erroneously applied to the wrong account. The fault in this case might have been in the communications channel (a garbled message),or in the system component that prepares the message for transmission. The error was applying the charges to the wrong account. The fact that the customer receives an incorrect charge is the failure, since they agreed with the carrier to pay for the service that they used and not for unused service.

Tanımlar ise aşağıda :
fault is the defect that is present in the system that can cause an error. It is the actual deviation from correctness.
An error is the incorrect behavior from which a failure may occur. Erros can be categorized into two types : timing or value
failure is system behavior that does not conform to the system specification.
Detection Patterns
Detection Patterns başlığı altında eğer hatadan kurtulmak mümkün değilse Fail Silent'ın tercih edilmesi önerilmiş.

The most desirable means of failure handling in a computing system is when the error is detected automatically and corrected before it beceoms a failure. If this is not possible and a failure occurs, then the next most favorable are the Fail Silent and then the Crash Failure mode.

Fail Silent Nedir ?
A Fail-Silent failure is one in which the failing unit either presents the correct result or  no result at all. A Crash Failure is one where the unit stops after the first silent failure.

Fail Silent Durumu İletilir mi ?
Bir başka paragrafta ise Fail Silent moduna giren birimin, durumunu başka birimlere bildirmemesi gerektiği anlatılmış.

When failing silently the erroneous element immediately stops processing without corrupting any of its peers. To ensure peers do not corrupt other peers through the error propagating, the failing element stops without informing them that it is stopping. The problem of detecting that an element has stopped functioning is a totally different and easier problem than the problem of determining if an element has stopped operating correctly.

VxWorks 653 Health Monitor

Health Monitor Nedir?

Health Monitor ARINC 653 standardından geliyor.Health Monitor herhangi bir hata durumunda ne yapılması gerektiğini belirten bir tablo gibi düşünülebilir. 


Hangi zamanda hangi seviye HM tablosunun kullanılacağı SystemState olarak anılan sistemin durumuna göre belirlenir. Örneğin partition normal mode'a gelmeden hata verirse module os seviyesindeki error handler çağırılır. Eğer bir hata, oluştuğu seviyede ele alınmaz ise, bir üst seviyeye çıkarılır ve bu seviyedeki error handler tarafından işlenir.

XML ile ayarlanabilen 3 seviyede mevcut. Bunlar "Process Seviyesi", "Partition Seviyesi", "Module Seviyesi". Process seviyesi haricindeki diğer tablolar XML ile giriliyor.

Aşağıda tüm XML'i kapatılmış olarak gösteren bir örnek var. ARINC 653 standardında olmayan SystemHMTable tablosunu da aşağıda açıkladım.
<HealthMonitor>
   <SystemHMTable/>

   <ModuleHMTable/>
   <PartitionHMTable>
</HealthMonitor>

Process Seviyesi Health Monitor Ayarları
Konuyu Process Seviyesi Health Monitor başlıklı yazıya taşıdım.

Partition Seviyesi Health Monitor Ayarları
Aşağıda bölümleme (partition) için XML örneği var.ErrorAction alanının karşısında yazan isim, hataya oluşunca çalıştırılması istenen kod parçasını belirtmek için kullanılıyor.

Her partition için ayrı bir HM tablosu bulunabilir. Eğer istenirse tüm partition'lar için aynı tablo da kullanılabilir.

Örnektede açıklandığı gibi, hmDefaultHandler partition'ı yeniden başlatır.hmDbgDefaultHandler ise partition'ı durdurur. Geliştirme aşamasında HME_HM_DEADLINE_MISSED hatası alınırsa partition'ın yeniden başlatılmasının sebebi budur.

<PartitionHMTable Name="partition1Hm">
 <SystemState>
  <ErrorIDAction Error Identifier="HME_UNKNOWN" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_NUMERIC_ERROR" ErrorAction=""/>
  <ErrorIDAction Error Identifier="HME_POWER_FAIL" ErrorAction="hmDH_HME_POWER_FAIL"/>
  <ErrorIDAction Error Identifier="HME_KERNEL" ErrorAction="hmDH_HME_KERNEL"/>
  <ErrorIDAction Error Identifier="HME_CONFIG_ERROR" ErrorAction="hmDH_EventLog"/>
  <ErrorIDAction Error Identifier="HME_INIT_ERROR" ErrorAction="hmDH_HME_INIT_ERROR"/>
  <ErrorIDAction Error Identifier="HME_PARTITION_OVERFLOW" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_PARTITION_MODE_SET" ErrorAction="hmDH_HME_PARTITION_MODE_SET"/>
  <ErrorIDAction Error Identifier="HME_APEX_INTERNAL_ERROR" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_HM_INTERNAL_ERROR" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_PORT_INTERNAL_ERROR" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_LOST_TICKS" ErrorAction="hmDM_LOST_TICKS"/>
  <ErrorIDAction Error Identifier="HME_HM_ERROR" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_HMQ_OVERFLOW" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HME_DATA_LOSS" ErrorAction=""/>
   <ErrorIDAction Error Identifier="HME_HM_DEADLINE_MISSED" ErrorAction="hmDefaultHandler"/>
  <ErrorIDAction Error Identifier="HM_MSG" ErrorAction="hmDH_EventLog"/>
  <ErrorIDAction Error Identifier="HME_DEFAULT" ErrorAction=""/>
 <Settings maxQueueDepth="34" queueThresHold="32" stackSize="16384" maxLogEntries="100" logEntriesThreshold="98" attributesMask="0x00000001" notificationHandler ="" notificationMaxQueueDepth="0" eventFilterMask="0xFFFFFFFF" maxErrorHandlerQueueDepth="128" errorHandlerQueueThreshold="126"
  </Settings>
  </SystemState>
</PartitionHMTable>

HME_LOST_TICKS: Such an event is received when system clock interrupts were lost

HME_POWER_FAIL: Such an event is received when the power source of the module failed for an amount of time less than the RAM holding time. This means that when this event is received the power should be back on, and the RAM should not be affected bythis short power loss. However all of the devices on the module have been reset.

XML ve Kod Eşleşmesi
XML'de tanımlanan isimler ile çağrılacak metodlar vxworks653-x.y.z.\target\config\comps\src\usrHm.c dosyasındaki tabloda eşleştiriliyor.

extern STATUS myHandler (HM_EVENT_ID event);

HM_HANDLER_TBL_ENTRY hmHandlerTbl [] =
{
    .....//Original handlers
    {"myHandler" ,myHandler}
};

Kendi Metodumuz
Eğer kendimiz yeni bir handler yazmak istersek, ModuleOS projesine yeni bir metod yazmalıyız ve metodu yukarıdaki tabloya eklemeliyiz. Yeni metodun imzası şöyle:

STATUS myHandler (HM_EVENT_ID event){
 return OK;
}

Module Seviyesi Health Monitor Ayarları
Bu tabl PartitionHMTable ile hemen hemen aynı olduğu için tekrar etmek istemedim.

System Seviyesi Health Monitor Ayarları
Aşağıdaki cümleler önemli
 * Defines the level of an error (Module, Partition, Process) based on the error and the state of the system.
Yani bu tablo bir çeşit dispatcher gibi çalışıyor. Gelen hatayı uygun olan seviyeye yönlendiriyor.

Bu tablo oldukça kısa.
<SystemHMTable Name="systemHm">
    <SystemState SystemState="HM_PARTITION_MODE">
        <ErrorIDLevel ErrorIdentifier="HME_DEFAULT" ErrorLevel="HM_PARTITION_LVL"/>
    </SystemState>
    <SystemState SystemState="HM_MODULE_MODE">
        <ErrorIDLevel ErrorIdentifier="HME_DEFAULT" ErrorLevel="HM_MODULE_LVL"/>
    </SystemState>
    <SystemState SystemState="HM_PROCESS_MODE">
        <ErrorIDLevel ErrorIdentifier="HME_DEFAULT" ErrorLevel="HM_MODULE_LVL"/>
    </SystemState>
</SystemHMTable>

VxWorks 653

Giriş
Havacılık dünyasında en çok kullanılan iki işletim sistemi var. İlki Green Hills Integrity, diğeri ise Wind River VxWorks. Benim gördüğü kadarıyla Türkiye'de Integrity daha fazla pazar payına sahip ve tercih ediliyor. VxWorks ise bir çok firma için bir muamma. Bu yüzden WxWorks'ü tanıtıcı bir yazı hazırladım. İleride Integrity için de bir yazı hazırlamayı planlıyorum.

WindRiver ve Destek
Eğer WindRiver firmasının verdiği destek iyi seviyede. Firmanın verdiği License Number , License Administrator Token, License Authorization Code bilgilerini saklamak gerekir.


IMA Nedir?
Aviyonik Mimariler yazısına taşıdım.

Havacılık Uygulamalarında Wind River Ne Sunuyordu?

VxWorks 653'ten önce havacılık uygulamaları için VxWorks Cert vardı. Bu işletim sistemi VxWorks 6.x tabanlı ve DO-178B Seviye A sertifikasyona sahip multitasking kabiliyetli bir işletim sistemi. Aşağıda broşürünü görebilirsiniz.




VxWorks 653 Nedir ?
VxWorks 653 havacılık ve savunma sanayi için özel olarak tasarlanmış bir işletim sistemi. Ares I sisteminde "Flight and command computer" olarak ta kullanıldığı yazıyor. Sanıyorum uzay sistemlerinde de kendine yer bulan/bulmaya başlayan bir işletim sistemi. VxWorks 653 de kendi içinde sürümlere sahip. VxWorks 653 2.1 veya VxWorks 653 3.2 gibi sürümlere denk gelebilirsiniz.

En önemli özelliği Integrated Moduler Avionics (IMA) yapısını desteklemesi. Şekilde bu durum görülebilir.

IMA'yı destelemek için VxWorks 653 işletim sistemi iki farklı parçaya bölünmüş. İlk parça "Module OS", diğeri ise "Partition OS". Tüm gömülü sistemlerde olduğu gibi her iki parça da projeyle beraber derlenip boot edilebilir bir halde karta yükleniyorlar.

Module OS
Module OS, Board Support Package (BSP) aracılığıyla donanım ile konuşuyor ve "Partition OS"'lerin zamanlamasından (scheduling) sorumlu. Burada dikkat edilmesi gereken nokta VxWorks dokümanları bazen Module OS yerine Core OS kelimesini de kullanıyor. Module OS ARINC 653 terminolojisinden geliyor. Core OS ise VxWorks 653 terminolojisi. Her iki kelime de aslında eş anlamlı. Core OS bölümlemeler arası mesajlaşmadan sorumlu.

CoreOS başlarken terminale
[coreOS] -> Loading symbol table for PartitionOS from PartitionOS.sym... done
yazar. Daha sonra her partition için
Loading symbol table for PartitionX from PartitionX.sym... done
yazar.

Module OS ve Scheduler
Aşağıdaki cümle önemli. Module OS ve Partition OS arasındaki temel farkı özetliyor.
By default the Core OS schedules partitions by time-preemptive scheduling (TPS) and in partition order.
Yani her bölümlenme kendisine verilen zaman kadar çalışıyor. Aralarında öncelik farkı yok. Tek istisnai durum ise yine aşağıda açıklanmış.
If a partition is enabled for priority-preemptive scheduling, the Core OS considers the partition for scheduling during the idle time within the TPS schedule.
Yani eğer idle zaman varsa, Core OS bu boşluğu bir bölümlenmeyi fazladan çalıştırmak için kullanabilir.

Partition OS
"Partition OS" ise bölümlenmeden sorumlu ve uygulamayı koşturuyor.Bölümleme içinde koşan uygulamalar işletim sistemine erişmek için standartlar ile belirlenmiş arayüzler kullanıyorlar. "Partition OS" bu standartları sağlamaktan sorumlu. Bu standartlar ARINC 653 API, POSIX API veya VxWorks Native API'den biri olabilir.

Partition OS threadlerine vThreads deniliyor. vThreads user-level thread'ler. Partition OS aslında VxWorks 5.x veya VxWorksCert mikrokernel'ine benziyor.  vThreads başka bir bölümlemeye ait kernel nesnelerine erişemez. Sadece kendi bölümlemesinin kernel nesnelerine erişebilir.

Partition OS donanımdan hiçbir şekilde kesme (interrupt) almaz. Core OS pseudo interrupt gönderir.

Eğer kendi Partition OS'umuzu geliştirmek istersek VxWorks COIL (Core OS Interface Library) isimli bir altyapı sağlıyor.

Partition OS'a bileşenler eklemek için PartitionOS.xml dosyasına bileşenin xml'ini eklemek lazım.

 Partition OS ve Scheduler
 Aşağıdaki cümledeki bilgi önemli.
The vThreads scheduler is a priority preemptive scheduler (PPS) that allocates CPU to the highest priority thread that is ready to run. 
Uygulama
Uygulama Partition OS header dosyalarını kullanıyor ve Partition OS ile linkleniyor. Uygulama projesi BSP ve donanımdan iyice yalıtıldığı için, donanımla alakalı herhangi bir ayar yapmak gerekmiyor. Sadece hangi CPU mimarisine göre derleneceği seçilebilir. Böylece uygulama projesi, farklı bir kart için derlenmek istenirse, rahatlıkla gerçekleştirilebilir.

VxWorks 653 Cert Nedir
VxWorks653 ile çalışırken oluşturulan proje Cert ise , burada yazdığına göre DO 178B Level A için gerekli isterleri karşılıyor.
VxWorks Cert Platform is backed by the industry’s most comprehensive set of certification artifacts, which support all RTCA DO-178B and EUROCAE ED-12B Level A requirements. 
VxWorks 653 ve XML Derleyicisi
VxWorks 653 ile bir çok ayar XML vasıtasıyla yapılıyor.  Daha sonra XML derleyicisi, XML dosyalarını binary veri haline getiriyor. Buradaki sunumda işleyiş görülebilir.

Bazı vThreads Bileşenleri
Konuyu VxWorks653 ve Partition OS Bileşenleri başlıklı yazıya taşıdım.

Core OS Bileşenleri
Core OS bileşenleri bir sihirbaz aracılığıyla eklenip çıkarılabilir.

Target resident shell
Linux'takine benzer bir kabuk çalıştırabilme imkanı sağlar.
devs : Sistemdeki yüklü aygıt sürücülerini gösterir.
Health Monitor
Konu uzun ve karışık olduğu için VxWorks 653 Health Monitor başlıklı yazıya taşıdım.

WorkBenchWorkbench kurulum dizininden itibaren workbenc-xy\wrwb\platform\x86-win32\eclipse\wrwb-x86-win32.exe

VxWorks 653 Integration Project
Yukarıda anlatılan VxWorks 653 projesini oluşturmak için "Integration Project" sihirbazını kullanıyoruz. Örnek:

Şekilde Module OS ve Partition OS projelerini ayrı ayrı görmek mümkün. Ayrıca yaratılan partitionlar da görülebilir. Config record içinde bazı ayarların yapıldığı XML dosyaları var ancak bu dosyalar Module OS için mi yoksa Partition OS içinmi kullanılıyor bilmiyorum.

Workbench ve Debug

Remote System Sekmesi
Workbench'te "Remote System" sekmesi target'a bağlantı kurmak için kullanılır. Açıklaması şöyle: "A connection to a target must be defined and established before tools can communicate with a target system. You establish this connection in the Remote Systems View." Bu sekmedeki bağlantıya sağ tıklayarak File alanına imajın yüklendiği boot.txt dosyasını göstermek lazım.

Bağlanıldığı zaman aşağıdaki yol takip edilerek örneğin Partition1'e target'a attach edilir.
Board Name -> Wind Reiver Target Debugger -> VxWorks 653 -> protection domains -> Partition 1  -> protection domain tasks
Bu menüye sağ tıklanır ve Debug -> Attach to all Protection domain taks veya Attach to all Protection domain taks and Threads (Task Mode)  menüsü seçilir. İkisi arasındaki farktan çok emin değilim ancak ikincisini seçersek işletim sisteminin kendi yarattığı taskları da gösteriyor.

Debug Sekmesi
Breakpoint koymak için kaynak dosyaların path'inin belirtilmesi gerekir. Bu sekmede sağ tıklayıp "Edit Source Lookup" menüsü ile kaynak dosyaların dizini belirtilir.

Terminate and Relaunch ile tekrar başlatılan target'a eski breakpointler yerleştirilir. Breakpoint koyarken eğer kaynak kod ile yüklenen binary (image) arasında uyumsuzluk varsa Workbench uyarı verir.

WDB
Wind Debug Agent target üzerinde debug yapılabilmesine imkan tanıyan bir Remote Debugger. UDP veya TCP 17185 numaralı portu kullanır. Aşağıda bir açıklama mevcut.

WDB'nin VxWorks'e erişebilmesi için, işletim sisteminin arayüzler (remote debugging interface routines) sağlaması gerekiyor.
Target açılırken VxWorks ASCII Art logosunun altın
CPU : ...
Memory Size : ...
WDB : Ready
yazar


Makefile
Konuyu Makefile Kullanma başlıklı yazıya taşıdım.
Not:
Konuyla ilgili olarak GNU Binary Araçları başlıklı yazıya bakabilirsiniz.

linkerscript
linkerscript'in tanımı burada. Konuyu sonra yazacağım.

Config Record XML'i

BlackBox

Bu xml içinde ELF formatında kullanılacak alanların büyüklüklerini ayarlıyoruz. Konuyla ilgili olarak VxWorks 653 ve Blackbox başlıklı yazıya göz atabilirsiniz.


Portlar
Konuyu VxWorks 653 ve Portlar başlıklı yazıya taşıdım.

Config Record XML'i İle Bölümlenme Zamanı
Bölümlenmelere ayrılan zamanı tanımlamak için kullanılan XML tag'leri ARINC 653 standardına uyumlu değil. Ancak bence anlaması daha kolay. Örnek'te iki farklı scheduler tanımlı. Sistem başka bir state'e geçerse (örneğin maintenance state'ı gibi 1 numaralı schedule etkinleştirilerek diğer bölümlemeler durdurulur) Default olarak 0 numaralı schedule başlar.

<Schedules>
<!- First partition->
 <Schedule Id="0">
   <PartitionWindow PartitionNameRef="Partition1" Duration="0.25" ReleasePoint="1">
   <PartitionWindow PartitionNameRef="Partition2" Duration="0.25" ReleasePoint="1">
 </Schedule>

<Schedule Id="1">
   <PartitionWindow PartitionNameRef="Partition3" Duration="0.25" ReleasePoint="1">
 </Schedule>
</Schedules>
PartitionNameRef alanı ile verilen bölümlenme ismi daha önce tanımlanmış bir bölümlenme olmalı. Duration ile verilen süre saniye cinsinden. ReleasePoint 1 ise partition başlayınca periodic task'ların başlamasını da sağlar.

ARINC 653 standardı ile kullanılan XML formatı ise aşağıda. Hiç benşmediklerini göstermek için ekledim. Örnek:

<ModuleSchedule>
  <!- First partition->
  <Partition_Schedule>
     <Window_Schedule>
  </Partition_Schedule>

  <!- Nth partition->
  <Partition_Schedule>
    <Window_Schedule>
   </Partition_Schedule>
</ModuleSchedule>

Main Metodu
VxWorks'te ile alışageldiğimiz main metodu yok. Programınız void usrAppInit (void) metodu ile başlıyor. Uygulamaya argv,arc parametreleri geçilmiyor. Örnek:

Eğer Linux'ta da çalışmak istersek aşağıdaki gibi yapabiliriz.
extern void myMainEntryPoint ();

void usrAppInit (void){
 /*add application specific code here*/
  myMainEntryPoint();
}

Linux projesindeki main dosyasında ise aşağıdaki gibi yapılır. ProcessEntry metodunda niçin sonsuz döngü olduğu burada açıklanıyor.

void ProcessEntry (){
  while (true){ //Loop forever
  }
}

void myMainEntryPoint(){
  CREATE_PROCESS (...); //Create ARINC process
  START (); //Start ARINC process
  SET_PARTITION_MODE (NORMAL);
  STOP_SELF ();
}

int main (int argc,char* argv[]){
   myMainEntryPoint();
}
system clock
Standart VxWorks'te iki çeşit clock var. Bunlar "system clock" ve aux clock". VxWorks 653'te bunlar kullanılabiliyormu bilmiyorum.

Ağdan boot
boot.txt aşağıdaki gibi olmalı
#Boot30
pwd://coreOS.sm -> Core OS için
pwd://vxSysLib.sm -> Sanırım Partition OS için
pwd://configRecord.reloc
pwd://partition1.sm -> Benim partitionım için
pwd://partition2.sm -> Benim partitionım için

Buradaki soruda ağdan ftp ile indirilen yazılımı boot ederken verdiği çıktı var. boot device : mottsec ethernet arayüzünü kullanarak boot et anlamına geliyor sanırım.

__ctypePtrGet
ctype.h dosyasında tanımlı olan isLower() benzeri karakterlerle ilgili olan metodların çalışabilmesi için lazım. Örnek:
 __ctypePtrGet() meodu vThreadsData.h dosyasında tanımlı. Bu yüzden bu dosyayı da #include <vThreadsData.h> satırı ile include etmek gerekiyor. Buradaki ve buradaki örneklerde görüldüğü gibi, ctype.h dosyasında extern olarak tanmlı olan bir değişkeni, kendi kaynak dosyamızda tanımlamak ve ilklemek gerekiyor. Sebebini ben de çok anlamadım ancak, gördüğüm örnekler böyleydi.

taskLock
taskLock() kilit bırakılıncaya kadar başka bir şeyin çalışmasına müsade etmez. Ancak burada problemli olduğu yazıyor. Sebebi ise açıklanmamış.

CDF Dosyaları
CDF Component Description Files anlamına gelir. VxWorks 653 konfigürasyonu 3 şekilde yapılır.
1. XML Configuration Files
2. Binary Component Files
3. Configlettes

CDF dosyaları binary component files için kullanılır. Wind River tarafından sağlanan bileşenler VxWorks 653 Component Reference kitabında anlatılıyor. CDF dosyasında binary component için konfigürasyon parametreleri tanımlanabilir. BSP'ye mahsus CDF dosyasını değiştirmek için \vxworks-x-y\target\config\mybsp\00bsp.cdf dosyası açılır ve CHILDREN ağacına INCLUDE_XYZ_END satırı eklenir.

Bu bileşenin konfigürasyonu ise dosyann alt tarafında

Component INCLUDe_XYZ_END{
} ile başlayan yere yazılır.

Configlettes
Module OS içindeki cdf dosyası derlenecek kod hakkında bilgi verir. CDF dosyasının içi:
CONFIGLETTES : Sürücünün kaynak kodunu içeren dosyaların isimleri.
INIT_RTN : Sürücünü etkinleşmesi için çağırılacak ilk metodun ismi
PROTOTYPE: İlk metodun imzası. Örnek: void myDriverInit(void);

VME
Askeri havacılıkta kullanılan sistemler bazen güçlendirilmiş VME kasa içine konulup, hava aracına takılıyor. Aşağıda sökmesi takması ve taşıması kolay olan ruggidized vme için bir örnek şekil var.

VxWorks 653 Process Seviyesi Health Monitor

Process Seviyesi Health Monitor Ayarları

XML haricinde uygulamamız için Health Monitoring işlevini yerine getiren kod yazmak ta mümkün.
There is potential for a process health monitor for each partition. The application must create the process health monitor by calling hmCreateErrorHandler (bu native API) or for ARINC 653 applications by issuing CREATE_ERROR_HANDLER. The routines create a highest priority task in the partition OS with which to run the process health monitor handler.

Uygulamamız için hata raise edilirse, SystemState uygulamayı belirteceği için kendi kodumuz çalışır.
Aşağıdaki cümleler önemli.
 * The HM will not violate partitioning when handling process level errors.
 * The error handler process is active in NORMAL mode only.

Error Handler Yaratmak

Eğer uygulamamız için de health monitor eklemek istiyorsak CREATE_ERROR_HANDLER metodunu kullanarak kod yazmamız gerekir. Buradaki açıklama önemli
The error handler task is invoked when the RTOS 653 health monitor detects a process level error
Aşağıda error handler yaratmak için örnek kod var:

STACK_SIZE_TYPE stackSize = 1024 // 1 KB
RETURN_CODE_TYPE returnCode;
//Shall create a special process with the highest priority, ENTRY_POINT and STACK_SIZE attributes.for the current partition,
CREATE_ERROR_HANDLER ((SYSTEM_ADDRESS_TYPE)ErrorHandler, stackSize, returnCode);

CREATE_ERROR_HANDLER Metodunun İçi

Metod içeride yeni bir task yaratıp bu task ile haberleşmek için msgQueue oluşturuyor.

CREATE_ERROR_HANDLER (SYSTEM_ADDRESS_TYPE ENTRY_POINT,
                                                       STACK_SIZE_TYPE STACK_SIZE,
                                                       RETURNCODE_TYPE* RETURNCODE) {
      //... do some stuff
   if (hmErrorHandlerCreate ((FUNCPTR)ENTRY_POINT,STACK_SIZE,1) {...}
}

hmErrorHandlerCreate Metodunun İçi

Aşağıdaki kod parçasında msgQCreate metodunun çağırıldığı görülebilir.

STATUS hmErrorHandlerCreate (...) {
   //... do some stuff
   hmCtxId->ehQueueId = msgQCreate (hmCtxId->ehMaxQueueDepth,
                                                                sizeof(HM_EVENT),
                                                                MSG_Q_FIFIO);

  hmCtxId->ehTaskId = taskCreat ("tHmErrorHandler"// task name
                                                        hmCtxId->ehTaskPrio, // 0. priority
                                                        options,
                                                        stackSize,
                                                        errorHandler,
                                                        param,
                                                        0,0,0,0,0,0,0,0,0);
}

Error Handler Metodunda Kullanılabilecek Çağrılar

VxWorks'ün sunduğu kütüphaneler kullanılabildiği gibi ARINC 653 portlarına da erişmek mümkün. Çünkü portlar partition seviyesinde açılıyor.

Error Handler Metoduna Gelen Hata Kodları
Error Handler metodunda yakalamamız gereken hata kodlarını açıklayan şu cümle önemli.
The following are process-level APEX error codes:
  • APPLICATION_ERROR
  • DEADLINE_MISSED
  • HARDWARE_FAULT
  • ILLEGAL_REQUEST
  • MEMORY_VIOLATION
  • NUMERIC_ERROR : Floating point işleminde overflow, sıfıra bölme vb. olursa bu hata gönderilir. 
  • POWER_FAIL
  • STACK_OVERFLOW
Örnek Error Handler Metodu

#include "taskLib.h"
//Hata alan uygulamayı durdurma örneği
void ApplErrorHandler (){
    ERROR_STATUS_TYPE errorStatus;
    RETURN_CODE_TYPE returnCode;

    while (true){
        GET_ERROR_STATUS  (&errorStatus,&returnCode);
        if (returnCode == NO_ERROR){
            switch (errorStatus.ERROR_CODE){
                case APPLICATION_ERROR:{
                    //Log error
                    printf ("Error code : %d %s \n",errorStatus.ERROR_CODE,errorStatus.MESSAGE);
             
                    //veya istenirse loglama amacıyla port'a yazılabilir
                    SEND_QUEUING_MESSAGE (portNo,
                                                                        errorStatus.MESSAGE,
                                                                        strlen(errorStatus.MESSAGE),
                                                                        0 , //timeout
                                                                        &returnCode);

                    //Suspend task for debugging

                    int taskId = taskIdFromProcIdGet (errorStatus.FAILED_PROCESS_ID);
                    taskSuspend (taskId);//tasklib icinde
                    break;
                }//case
            }//switch
        }//if
        STOP_SELF();
    }//while
}

Klasik Bir Error Handler
Klasik bir error handler içinde call stack yazdırılır ve hata veren partition durdurulur. Hata adresini almak için taskInfo kütüphanesindeki taskRegsGet() kullanılabilir.

int taskId = taskIdFromProcIdGet (errorStatus.FAILED_PROCESS_ID);
REG_SET regs;
//Get CPU registers with VxWorks native api
if (taskRegsGet (taskId,&reg) ==  OK){
  printf ("0x%.8x",regs.gpr [1]);//General Purpose Register error address

}

Bir başka örnekte traceLib içindeki trcStack() metodu kullanılmış.

REG_SET regs;
taskRegsGet(taskId, &regs);
trcStack(&regs, (FUNCPTR) wpiCleanTracePrint, taskId);