天天看點

Ubuntu16.04 Xenomai3.x 系列移植筆記----測試與程式設計運作應用程式實時的I / O的支援RTnet 測試RTnet程式設計代碼

目錄

建構一個xenomai 3 應用

編譯一個基于rtdm的子產品

運作應用程式

運作一個xenomai 3應用

實時的I / O的支援

關于RTnet

RTnet相關特性

RTnet 基本要素

RTnet 配置檔案

RTnet 測試

RTnet程式設計代碼

建構一個xenomai 3 應用

詳細的建構與安裝見https://gitlab.denx.de/Xenomai/xenomai/-/wikis/App_Setup_And_Init

總而言之,您應該使用xeno-config腳本來擷取适當的編譯和連結器标志相關的Xenomai,以便

建構您的應用程式的Cobalt or Mercury core.

xeno-config腳本的完整用法可在以下https://xenomai.org/documentation/xenomai-3/html/man1/xeno-config/index.html找到。

對于沒有耐心的人,這裡有一個簡單的Makefile片段,用于檢索編譯器和用于建構單檔案應用程式vxapp.c的标志,通過VxWorks仿真API:

XENO_CONFIG := /usr/xenomai/bin/xeno-config 
CFLAGS := $(shell $(XENO_CONFIG) --vxworks --cflags) 
LDFLAGS := $(shell $(XENO_CONFIG) --vxworks --ldflags) 
CC := $(shell $(XENO_CONFIG) --cc) EXECUTABLE := vxapp 
all: $(EXECUTABLE) 
%: %.c 
$(CC) -o [email protected] $< $(CFLAGS) $(LDFLAGS)
           

編譯一個基于rtdm的子產品

建構正常核心子產品/驅動程式的規則也适用于基于rtdm的驅動程式,不需要額外的要求。

例如,用于建構some_driver.ko的Makefile,由foo.c和bar.c兩個檔案組成,基于RTDM API:

obj-y += some_driver.o 
some_driver-y := foo.o bar.o
           

從核心樹建構這個子產品應該從包含子產品源的目錄中完成,如下所示:

$ make -C /path/to/kernel/tree M=$PWD modules
           

從核心樹建構這個子產品應該在包含驅動程式子產品的目錄中完成,在為雙重核心配置建構驅動程式子產品之前,目标核心樹必須已經準備好并按照這裡的文檔進行建構。

運作應用程式

運作一個xenomai 3應用

對于Cobalt 核心來說,您需要将實時核心建構到目标Linux核心中,安裝描述步驟:https://gitlab.denx.de/Xenomai/xenomai/-/wikis/Installing_Xenomai_3

對于Mercury 核心來說,到目前為止,您不需要特定于xenomai的核心支援,除了您的主機Linux核心已經提供的。您的核心至少應該提供高分辨率計時器支援(CONFIG_HIGH_RES_TIMERS)

如果您的應用程式需要短且有限制的延遲,則可能需要完全搶占(PREEMPT_RT)。任何基于xenomai的應用程式都可以識别一組可以在指令行上傳遞的标準選項,如本文檔所述。

此外,運作在Xenomai核心上的Alchemy、pSOS和VxWorks™api可以定義要使用的時鐘分辨率,以納米秒為機關,即HZ=(1000000000 / ns),由--{Alchemy / pSOS / VxWorks}-clock-resolution=<ns>選項。

如果您的應用程式組合了多個api,您可以通過幾個時鐘分辨率開關來設定它們。預設值取決于所考慮的API。例如,VxWorks™和pSOS™模拟器預設為毫秒時鐘速率。Alchemy API預設是無标記的,即--Alchemy -clock-resolution=1。指定大于1納秒的分辨率需要Xenomai庫提供低分辨率時鐘支援(請參閱--enable-lores-clock configuration開關)。

實時的I / O的支援

Real-time networking (RTnet)

  • 關于RTnet

RTnet的設計目的是為RTAl和Xenomai環境提供實時網絡功能。本檔案旨在為使用Xenomai進入RTnet的初學者提供一個跳闆。

RTnet項目的代碼以子產品化的方式組織。通常的biq圖像是TDMA實時現場總線,但是您也可以使用RTnet執行更簡單的任務,比如實時點對點通信。對于更簡單的任務,可能不需要全部RTnet。

  • RTnet相關特性

安裝好RTnet後有兩個檔案夾需要注意:

  1. 源檔案

預設位址:_/usr/src/rtnet-x.y.z .

特别需要注意:

*/Documentation :包含RTnet功能的結構和使用的基本資訊

*/example:包含已編譯并放在該檔案的的執行個體的源代碼

  1. 安裝檔案

預設位址:/usr/local/rtnet.

安裝檔案夾包含運作RTnet所需的所有已編譯的可執行檔案和核心子產品

etc:RTnet的兩個安裝配置檔案位于此檔案夾中。rtnet.conf和tdma.conf設定。

examples: 編譯後的RTnet示例放在這裡

sbin:在此檔案夾中,有各種用于運作和配置RTnet的腳本。

include:該檔案夾包含将用于編譯任何RTnet程式的包含檔案。

modules: 為RTnet編譯的子產品和使它與實時裝置驅動程式一起高效運作的所有元件都位于這裡

  • RTnet 基本要素

使用以太網時,通信是不确定的,因為在網絡上有一個集線器的幾個主機之間可能會發生沖突,或者由于交換機的延遲未知以。

太網協定不允許确定性通信,因為可能會發生沖突,并由CSMA/CD機制(載波感覺多址/沖突檢測)支援。

RTnet是一個協定棧,它運作在以太網層和應用層(或IP層)之間。它的目的是通過使用時間間隔(時隙)來進行确定性通信,通過禁用碰撞檢測CSMA/CD,防止網絡中的緩沖包。RTnet是一款在Linux核心上運作的軟體,具有RTAl或Xenomai實時擴充。它利用實時核心擴充來保證通信棧的确定性。在這個目标中,所有與此協定相關的指令都使用實時核心函數,而不是Linux函數,這些函數将延遲綁定到執行時間和中斷延遲,進而提供确定性的通信

  1. TDMA操作

通信分時段TDMA(時分多址)是協定決定論的基礎。使用配置設定給主機發送資料的時間間隔(時間槽)不能再使用沖突檢測機制(CDMA / CD),是以限制了消息的發送和接收之間的時間間隔。基于主從操作來同步網絡中每台主機的時鐘并為每台主機配置設定時隙,協定主要依賴于定期發出同步消息的主機。Wiki: tdma.png ?600

  1. 同步

Rtnet采用時分多路複用TDMA(時分多址),避免了通信沖突,在每個周期的開始,主機發送一個包含全局時鐘資訊的幀進行同步。同步幀在網絡和包含一個周期的定期發送4個位元組編碼數量,大師的參考時間的價值在納秒和傳輸參考時間的值,這個值有助于減少全球時鐘的偏差。同步消息包含以下資料:為了彌補集中式主從系統的不足,可以通過為備份主系統預訂額外的插槽來建立備用主系統(備份主系統)。如果主主系統崩潰,則在考慮到前一幀同步的變化之後,将激活輔助主系統。當主主伺服器恢複服務時,它與活動的輔助主伺服器同步,然後禁用輔助主伺服器。

  1. 協定棧

Rtnet協定棧包含OSI模型傳輸層的實體部分。它是專門針對實時核心RTAl和Xenomai開發的。為了保證通信應用的确定性,所有功能使用的以太網控制器應用軟體都必須滿足硬實時限制。是以,為了使用Linux的實時核心而不是通常使用的核心,必須實作網絡laver協定,特别是傳輸協定。Wiki: pile.png

  1. 實體層

實體層由以太網控制器支援,需要使用從Linux派生的特定驅動程式。處理記憶體、中斷處理機制或屏蔽中斷需要實時核心執行操作,以確定确定性。還要考慮在以太網驅動程式中最準确地檢測發射和接收的可能瞬間。從材料的角度來看,可以使用任何以太網控制器,并支援其他實體層(如火線)。管理控制器的初始化、設定和關機是不實時的,是以要特别注意收發功能。在發送時,儲存全局時鐘的值,在接收時,需要儲存接收時的全局時鐘的值,以便精确控制。

  1. 資料鍊路層

以太網作為一種标準操作,不能提供硬實時通信,無論是在基于中繼器的網絡上,還是在存在沖突風險的交換機上。IEEE 802.1q提供的服務品質為這個問題提供了一個很好的解決方案,但是交換機的集中是昂貴的布線。Rtnet的資料鍊路協定是由核心子產品Rtmac提供的,它包含一個子產品TDMA。TDMA子產品管理網絡上的通信(同步、周期時間等)。雖然這一層是stack Rtnet的可選擴充,但它帶來了基于這些服務的确定性媒體通路協定:

*将特定封包傳送至适當的服務

*使用高層協定交換控制消息和資料。

*在使用多個網絡接口的情況下,可以定義特定于媒體通路控制的接口。

*通過服務隧道與非實時網絡交換資料。

Rtmac層是一個提供以下服務的子產品:

*截獲包資訊,将它們重定向到适當的服務。

*上層并行資料應用程式中控制資料或特定資訊的交換。

*通過建立隧道與非實時系統進行通信

*使用一個虛拟接口并添加一個标頭來區分這個流。

  1. TDMA層

Rtnet在資料鍊路層采用時分接入網,防止發生資料沖突。該協定利用主從通信對網段節點的時鐘進行同步,并對周期性傳輸的同步消息定義了資料的傳輸時間。如果一個節點知道自己的時間通路權限,那麼它甚至可以在網絡啟動時加入網絡,并在該節點上手動配置或在網絡節點(rtcfa)上設定伺服器配置。一旦獲得該參數,節點将通過向主同步發送查詢來評估傳回網絡的時間,主同步将通過在發送的包中包含可以計算傳回時間的計時資訊來響應。

  1. 網絡和傳輸層

通過簡化路由過程和碎片優化,支援UDP/ IP和TCP/ IP網絡和傳輸層。位址解析協定(ARP)隻在初始化期間進行操作。在總線上的通信環境中,這些協定可能是不必要的,但是與外部網絡的通信相關,通常是非實時的。IP協定實作在實時核心上運作,并支援發送大小超過MTU(最大傳輸單元)的資料包的分段。為了執行路由,需要使用兩個表,第一個表是任務的路由表,它包含在LAN上可以通路的主機的IP位址。第二個表是可選的,它将網關位址實時地用于其他網絡,允許建立結構更複雜的網絡。路由表的内容類似于标準IP棧的ARP表。對于Rtnet,此表用于路由過程,而對于标準電池則不一定如此。UDP和TCP在IP層(版本4)之上實作,UDP用于硬實時傳輸。反過來,TCP最近已經實作,其目的是與不運作Rtnet的網絡元素進行通信,TCP要複雜得多(在一百多個RFC中進行了描述)。是以,由于其用途有限,它的實作已大大簡化。UDP則是預設協定,用于在兩個Rtnet應用程式之間建立實時通信。Rtcfg是為Rtnet有效配置網絡而定義的協定。為此,将網絡節點用作伺服器并将配置資訊發送給其他節點(用戶端)。由于虛拟接口的存在,可以運作所有網絡層協定并在更高标準的Linux核心中實作。也有可能對于有限的通信網絡節點不使用路由協定和傳輸(socket類型RAW)。

  • RTnet 配置檔案

。當啟動rtnet啟動腳本時,将讀取rtnet.conf檔案,并在啟動時設定rtnet環境。下面讨論這個檔案中的條目:(**********重要**********)

RT_DRIVER:RT驅動程式:此條目指定用于運作網卡的實時驅動程式。不是所有的網卡都支援RTnet,要找到支援的驅動程式,請檢視/drivers下驅動程式的源代碼。編譯後的驅動程式位于/modules…

RT_DRIVER_OPTIONS:RT驅動程式選項:系統上可能安裝多個網卡。要識别RTnet應該使用哪張卡,此條目用1指定它。為了找出哪張卡是由設定配置中的哪一個位置表示的,請更改1的位置并在主模式下啟動rtnet。當你把網線插入集線器時,活動卡的LED會不停地閃爍,就像它在尋找從機一樣……

IPADDR:主機IP

NETMASK:子網路遮罩

RT_LOOPBACK:如果在RTnet的安裝設定中選擇了LOOPBACK選項,那麼您可以使用此條目指定環回裝置是否處于活動狀态。此環回用于測試RTnet的正确工作方式,請參閱安裝說明了解更多資訊

使用細節:

RTCAP :RTCAP:為了能夠使用帶有RTnet的以太網絡分析儀,使用此條目。這也隻有在實時捕獲支援在RTnet安裝時被選中時才有效。更多資訊參見 /Documentation/README.rtcap 或https://www.rts.uni-hannover.de/rtnet/download/RTnet-ETFA05.pdf

TDMA_MODE :指定目前系統是主伺服器還是客戶機

TDMA_SLAVES : 當這個系統被設定為主機時,那麼網絡上的從機必須列在這裡。如果該系統被設定為從屬系統,請保留白白

TDMA_CYCLE : TDMA周期:對于簡單的TMDA設定,這裡列出了以微秒為機關的TDMA周期時間,僅當系統設定為主系統時使用。

TDMA_OFFSET :。TDMA偏移量:對于簡單的TMDA設定,這裡列出了以微秒為機關的TDMA偏移時間,僅當系統設定為主系統時使用。

TDMA_CONFIG : TDMA配置:當沒有使用簡單的TDMA設定,而需要更複雜的設定時,該條目指定要使用的TDMA配置檔案。它通常位于/etc/tdma.conf。更多設定細節/Documentation/README.rtmac

  • RTnet 測試

  • 單節點測試(本地回路)

檢測程式如下:

從正常的非實時ehternet網絡中斷開RTnet節點的網絡電纜

重新啟動系統到更新檔的核心模式

使用該指令顯示網絡設定

ifconfig
           

這将顯示你有運作的etho(這是你的網卡)和運作的lo(這是本地環回)

您需要禁用網卡的非實時網絡操作如下:

ifconfig eth0 down
           

然後,解除安裝網卡的裝置驅動程式。

sudo rmmod 8139too
           

加載RTnet操作所需的實時Linux擴充所需的子產品,如果你在xenomai2.x 建構核心時支援了RTDM,或者你正在運作xenomai3.x,跳過此步驟

在位于/usr/ocal/rtnet/etc/rtnet.conf的RTnet配置檔案中編輯以下參數:

sudo ./rtnet start
           

RTnet正在等待連接配接。cntl +C結束等待。通過調用Ismod并在加載的子產品清單中查找網卡的實時驅動程式,可以看到RTnet正在運作。如果未列出,則RTnet沒有運作

按如下方式Ping局部環回

sudo ./rtping 127.0.0.1

若要停止RTnet傳輸,請運作:

sudo ./rtnet stop

  1. 多節點測試

測試程式如下:

從普通的非實時以太網網絡中斷開RTnet節點。

使用開關(或集線器)将RTnet節點彼此連接配接。

重新啟動系統到更新檔的核心模式。

修改rtnet配置檔案/usr/local/rtnet/etc/rtnet.conf。你應該檢查以下内容:

sudo ./rtnet start

使用以下指令檢查節點之間的通信,其中為遠端節點的IP位址:

sudo ./rtping IP

停止指令 ctrl+C

解除安裝RTnet子產品

sudo ./rtnet stop

  1. Debugging RTnet

如果RTnet不能工作,或者隻能間歇性地工作,那麼很可能是由于這些已知的問題之一造成的

①Xenomai在你的硬體上不能正常工作。

②将用于實時網絡裝置的Linux驅動程式建構到核心中,并阻塞硬體。

③IRQ沖突。Xenomai能夠檢測沖突并将它們報告到核心控制台。

④您使用的是rt e1000驅動程式和RTnet 0.9.9或更老版本。請參閱RTnet: rte1000檢視解決方案。

解決問題的步驟:。

①檢查核心控制台或系統日志是否有可疑消息。

②驗證明時擴充的基本測試是否正常工作。Xenomai 還有一個基本的測試叫 latency

③收集有關您的設定(版本、配置、輸出消息)的資訊,并在rtnet使用者上釋出支援請求

  1. 同時使用實時(RTnet)和非實時網絡

如果您的系統上有兩條(或更多)以太網線路可用,您可以确定其中一條使用RTnet(實時),另一條使用非實時網絡:

①解除安裝非實時驅動程式

② 加載網卡驅動并指定網卡參數(e.g. insmod rt_e1000.ko cards=1,0).

③加載非實時子產品并啟動它(使用insmod和ifup的标準方式)。

網卡 參數接受一個由0和1組成的數組。例如insmod rt e1000.ko card=0,1,0 使用3的“中間”網卡。

$ sudo insmod /usr/local/rtnet/modules/rt_e1000.ko cards=1,0 $ sudo insmod e1000 $ sudo ifup eth1

  • RTnet程式設計代碼

介紹

一旦您了解了RTnet如何與RTOS相關的概念,在RTnet中進行程式設計就非常簡單了。

RTnet本身實際上隻是一個核心子產品,它與實時以太網裝置驅動程式通信RTnet和RTOS之間的接口是由Xenomai實作的實時驅動程式Modell提供的。該接口在Xenomai文檔中有完整的文檔記錄。

RTDM規範位于Xenomai API樹的子產品/實時驅動程式模型/使用者APl部分。

基礎引導

為了在RTnet中程式設計,遵循了标準的Linux套接字程式設計方法。如果您不熟悉Linux套接字程式設計,下面的連結将提供關于這個主題的一些額外資訊。

本機rt dev xxx與POSIX服務調用(使用Xenomai)的差別:

Xenomai應用程式獨立于RTnet,可以調用Linux的正常網絡服務。他們隻是在那一點上失去了時間保證。

POSI皮膚的程式設計模型允許您像編寫普通的Linux應用程式一樣使用套接字函數。如果您的呼叫位址是RTnet提供的服務(UDP或AF包),并且加載了RTnet,它将在實時限制下為您處理。RTnet不知道的服務被傳遞到Linux,沒有時間隔離。順便說一句,同樣的模式也适用于AF CAN。

(兩點從RTnet郵件清單中複制)

RTnet中的示例項目提供了在這種環境中進行程式設計的基本介紹。例子中的一般步驟如下:

聲明兩個套接字描述符結構,一個用于本地套接字,另一個用于遠端套接字。

static struct sockaddr_in local_addr; 
static struct sockaddr_in server_addr;
           

在用值填充這些結構之前清除它們

memset(&local_addr, 0, sizeof(struct sockaddr_in)); 
memset(&server_addr, 0, sizeof(struct sockaddr_in));
           

将位址格式設定為Internet (IP)

local_addr.sin_family = AF_INET;
           

将本地位址設定為主機位址

local_addr.sin_addr.s_addr = INADDR_ANY;
           

将sting轉換為端口号并将其存儲在結構中

local_addr.sin_port = htons(atoi(argv[1]));
           

對于遠端端口設定,再次将裝置格式設定為IP

server_addr.sin_family = AF_INET;
           

将IP位址sting轉換為網絡格式

server_addr.sin_addr.s_addr = rt_inet_aton(argv[2]);
           

設定遠端端口号

server_addr.sin_port = htons(atoi(argv[3]));
           

建立一個新的套接字來管理連接配接。

sockfd = rt_dev_socket(AF_INET, SOCK_DGRAM, 0);
           

将新的套接字綁定到本地端口

ret = rt_dev_bind(sockfd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
           

将套接字連接配接到遠端端口

rt_dev_connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
           

然後發送資訊。

rt_dev_send(sockfd, msg, sizeof(msg), 0);
           

在接收端接收消息

ret = rt_dev_recv(sockfd, msg, sizeof(msg), 0); 
* Close the socket after transmission 
-------------------- 
rt_dev_close(sockfd); 
---------------------
           

繼續閱讀