SCREAM Linux Middleware
User's Manual
SCREAM Lab., CSIE, NCKU
First Edition
April. 2007
SCREAM Lab.,
Department of Computer Science and Information Engineering
Nation Cheng-Kung University
Taiwan, ROC.
Reversion History
日期 |
版本 |
修改/新增 |
負責人 |
2007/04/19 |
1.0 |
Initial Version |
starryalley |
2007/04/28 |
1.0.1 |
Revised fonts for source codes and added some sections |
starryalley |
2007/05/30 |
1.0.2 |
Revised Figures and Formats |
starryalley |
SLIM使用者說明手冊
目錄
1. GENERAL INFORMATION 5
1.1 Component-based Software Development 5
1.2 SLIM System Overview 6
1.3 Authorized Use Permission 7
1.4 Organization of the Manual 7
1.5 Acronyms and Abbreviations 8
2. GETTING STARTED 11
2.1 Overall System Structure 11
2.2 SLIM Concept 13
2.3 Installation and Setup of SLIM 14
2.3.1 Installation and Setup from SLIM Source codes 14
2.3.2 Installation and Setup from SLIM Binary Release 17
2.3.3 API Documentation 19
2.3.4 SLIM Directory Layout 20
2.4 Building Blocks 21
2.4.1 Designing SLIM Components 22
2.4.2 Using Communication Channels 26
2.4.3 SLIM Component Generation Tool 28
2.5 Applications on SLIM 36
2.6 Interactive Shell of SLIM 38
2.7 SLIM Application Code Generation Tool 46
3. USING SLIM 50
3.1 Command Interface of islim 50
3.1.1 SLIM System Configuration 51
3.1.2 Execution Control 53
3.1.3 Project Manipulation 53
3.1.4 Information Display and Status Querying 55
3.1.5 Others 58
3.2 Eclipse Plugin 58
3.2.1 SLIM Eclipse Pluging Setup 59
3.2.2 Composing Tool 59
3.2.3 Execution and Information Tool 59
4. SOFTWARE DEVELOPMENT ON SLIM 61
4.1 SLIM Internal and Development 61
4.1.1 SLIM and The Concept of CBSD 61
4.1.2 SLIM System Architecture 63
4.1.3 Development Procedure with SLIM 66
4.2 Programming of SLIM Components 67
4.2.1 Programming API 67
4.2.2 Communication Between Components 73
4.3 Compiling of SLIM Components 76
4.4 Debugging and Testing of SLIM Components 78
4.5 SLIM Application Code Generation 80
5. Application Examples 82
5.1 File Reader/Writer 82
5.2 Timer 82
5.3 Audio/Video Player 83
5.4 Audio/Video Codecs 84
5.5 Play Control 85
5.6 Binding with JACK Audio Connection Kit 87
6. FAQ 93
7. Troubleshooting 98
Appendix A 103
元件式軟體開發(component-based software development)是 一種軟體開發方式,主要概念是將軟體依其架構與功能性分為多個獨立元件,在軟體開發過程中獨立開發這些元件,其後將各元件連接組合起來,完成最終應用程式 的一種軟體開發方式。元件導向式軟體開發之目的在於加強軟體的可重複利用性與彈性,並提供軟體開發者一個更方便、快速且容易使用的軟體開發方式。
元件(component)是一個抽象概念,可以是一個獨立運行的軟體實體,或是一個必須依賴其他元件,與之連結後才能正常運作的軟體。元件必須運行於一個軟體平台(application server)之上,該平台即是本系統(SLIM)之所謂中介軟體,提供元件執行運作的環境。中介軟體本身並提供一些如記憶體管理、元件組合與連接工具、執行緒支援、管理與監察元件之服務,並提供元件開發者一個共用的程式設計函式庫(API),使其可以與該平台上的其他元件溝通,亦或取得作業系統(host operating system)提供的服務。
元件式軟體開發被認為是提高軟體開發效率和質量的有效方式之一,且在目前各大軟體專案,以及分散式系統中得到廣泛的應用。元件式軟體開發簡單來說,就是透過開發各個軟體元件(software components),最後再將各個軟體元件組合起來,完成軟體開發的一種模式。這樣的概念類似物件導向的概念。
軟體元件是物件導向概念的延伸,將物件導向的概念之上再建立一層抽象層(abstraction layer),將程式分割成較小的組合單元(building Block),兩者皆強調軟體再用性(reusability),並強調物件或元件間的介面溝通能力。
元件內部實作通常不為外界所能看到,即是具有如物件導向概念中的封裝(encapsulation),且實作的修改通常並不影響使用者端的程式,而元件間的溝通管道與其介面則是在執行該軟體元件的平台建立之時就已經定義,並不需要元件開發者重新設計。
軟體元件是軟體重用(software reuse)的基本單元,透過完整且固定的一組介面定義對外連接(connecting, or binding),使的元件式軟體開發更容易達到重用效果。以元件實作方面來說,一個軟體物件必須要遵守其對外連接的介面,才能成為一個元件。
元件式軟體開發的優點包含提升軟體重用性、提高軟體維護性等。因此目前軟體界中已經有多個成功採用元件式軟體開發的軟體工具,如Microsoft的COM(Component Object Model)技術、OMG(Object Management Group)提出的CORBA(Common Object Request Broker Architecture)、用於Mozilla軟體平台的XPCOM(Cross Platform Component Object Model)、Sun提出的EJB(Enterprise Java Beans)、OpenOffice.org中的UNO(Universal Network Object)等等。所有這些平台中的元件式概念皆應用於多個程式語言互相溝通,或是透過網路來達成遠端互相通訊的目的,抑或把軟體分割為多個元件,並利用這些元件組成一個完整的應用程式。
SLIM(SCREAM Linux Middleware)為一個適用於桌上型或嵌入式系統上的中介軟體層,提供軟體開發者一個便於開發的整合型軟體開發介面,核心概念為軟體重用(software reuse)與物件導向設計(object-oriented design),利用模組化設計提供完整應用程式之開發平台。SLIM同時也是本實驗室(SCREAM Lab., NCKU)之類似軟體SMP(SCREAM Multimedia Platform)於Linux的版本,同時改良內部設計與運作模式。
SLIM同時也是一個架構於Linux作業系統之上的runtime layer,提供應用程式使用者一個隱藏式介面,最終軟體呈現方式將與一般獨立運作之應用程式(不透過SLIM執行)時相似。
於SLIM之上的軟體開發遵照元件式軟體開發(Component-based software development, CBSD)流程,主要目標使用者在於嵌入式軟體開發者,SLIM提供容易整合各式硬體之模組,並統一各模組間之溝通協定,統合許多功能之模組,讓開發者達成容易、快速,以及穩定有效率的軟體開發。
本實驗初期為了整合內部軟體組研究員之應用程式,特別設計一套元件導向式之軟體平台,參考Microsoft之DirectShow之GraphEdit軟體,藉以連接各軟體元件以達成一個應用程式開發。
本系統為成功大學資訊工程系,音樂多媒體實驗室(SCREAM Lab)之研究成果,系統程式原始碼同本使用者說明文件目前還未採用特定授權,但預計於未來日漸成熟後以GNU GPL方式發行。關於授權問題,請聯絡本實驗取得最新資訊。
本系統之原始概念為蘇文鈺老師,同學生al, showmin, neq, fruitfox, mobo, starryalley, keiko發展而來。Windows版相關程式為showmin, fruitfox, neq開發,名為SMP(SCREAM Multimedia Platform)。現由showmin維護,並已著手開發適合WinCE嵌入式系統之版本,名稱暫定為SWIM (SCREAM WIndows Middleware)。本系統目前由starryalley, mobo與keiko負責開發,由starryalley負責整合與維護,並撰寫本說明文件。
本說明文件分為7個章節,提供SLIM使用者(於SLIM之上開發軟體的使用者)關於本系統之詳細使用方式與概念說明。第一章為系統概述,第二章為快速開始使用之簡易說明,三四章為詳細之系統架構與使用說明,第五章則為範例實作之介紹與設計元件、撰寫程式碼之參考,第六七章則為常問問題集與問題排除。
第一章為系統概述,簡易說明本系統之概念,並說明本系統與本文件之授權。另外本文所有簡寫與縮寫可於1.5節中查詢。
第二章起為本文件內容開始。第二章為Getting Started,提供使用者快速使用本系統之簡易操作說明,包含本系統之設計概念與各子系統之簡易使用說明。使用者若需快速上手,則可從此章下手,並配合第五章的實例,得以快速使用SLIM開發軟體。
第三、四章為第二章之詳細說明,分別為使用SLIM之各子系統詳細介紹,以及利用SLIM開發軟體之詳細說明。包括本系統之所有功能、概念、與操作說明皆可於第三章中找到,其他任何有關軟體開發與程式設計,則於第四章中詳細說明。軟體開發者必須詳細閱讀此二章節,了解所有於本系統開發軟體之注意事項。
第五章為利用SLIM開發軟體的實作範例與介紹。其中介紹多個現有應用之開發設計流程、功能介紹,並展示本系統之功能。使用者可配合第二章簡易介紹,跳過三四章直接閱讀本章,得以取得大致上開發的模式流程概念。
第六章為常見問題集,所有常問問題在本章可以查詢。第七章則為問題排除。若遭遇任何操作上或執行上之問題,可於此章查詢解決方案。
本節列出所有於本文件出現之簡寫與縮寫,並不再於說明文件本文中再加以敘述。
SMP: SCREAM Multimedia Platform (Windows版元件導向式軟體開發平台)
SLIM: SCREAM Linux Middleware (Linux嵌入式軟體整合型開發平台與中介軟體)
component: SLIM上的一個元件
communication channel / data channel : SLIM上元件與元件間溝通的管道
gcc/g++: GNU C/C++ Compiler
gdb: GNU Debugger
Makefile: GNU Make之描述檔
另外於本文件中,有些命名由於SLIM前身為SMP之故,因此有關程式碼、實作的部份有些函式、功能,目前皆保留舊名,為了方便查閱起見,特別列出新舊名稱的對照如下:
SMP: 於程式碼部份代表現在的SLIM
filter: 等同於SLIM component,為SMP時的元件
(data) buffer: 等同於SLIM communication channel中的Data channel (同步)
signal buffer: 等同於SLIM communication channel中的Signal channel (非同步)
SLIM為協助軟體開發者的開發工具,系統運作模式大致上具有以下三個元素,分別為SLIM之中介軟體本身、SLIM開發工具,與在SLIM上運行之應用軟體。關係如圖1所示。
Figure
1: SLIM系統運作模式
SLIM Runtime Layer為支援於其上開發而成的各個應用程式的中介軟體層,直接架構於底層的作業系統之上。於SLIM上開發的各個應用程式必須依照SLIM上的元件介面來做開發,而成為SLIM專屬之應用程式。開發工具則包含GNU開發工具鏈(GNU Toolchain)的工具程式,未來並朝嵌入式系統之整合型開發環境(Integrated Development Environment, IDE)發展,架構於Eclipse平台上的SLIM外掛程式(plug-in),將於Eclipse中建立專屬SLIM的開發介面與工具,其中包含一個控制SLIM Runtime Layer以及應用程式執行的圖形化控制介面。在Eclipse的SLIM外掛程式完成之前,SLIM目前使用一個類似Unix中Shell概念的文字介面控制程式,稱為Interactive Shell of SLIM (islim),於2.6和3.1節將詳述。
SLIM的潛在使用者分為兩群,一為於SLIM平台上開發軟體的軟體開發者,二為使用架構於SLIM上的軟體的終端使用者(end user)。二者所見之SLIM各有不同,分別敘述如下:
軟體開發者(software developer on SLIM):
軟體開發者將可透過Development
tools等各種開發工具開發元件,並於islim工具測試開發中的軟體,配合gdb等除錯工具作開發。隨後透過code
generation工具產生應用程式原始碼,透過gcc等工具產生應用程式。
終端軟體使用者(software end user):
普通使用者使用之軟體雖架構於SLIM之上,但其將完全看不見SLIM runtime layer的存在,因此只見到上圖Application的部份。
有關開發工具詳述於第3、4章,工具類別主要分為以下幾個部份:
Runtime Layer:SLIM的核心部份;
Composer:元件組合工具;
Component Designer:元件介面與程式碼設計工具,架構於Eclipse平台之上;
Interactive shell of SLIM (islim):SLIM上的shell介面,開發者可以在其上控制軟體的執行,並做測試與除錯。
因此整個SLIM的子系統組合成一個軟體整合開發平台,包含執行時期的SLIM核心,適合軟體開發者使用的開發工具以及測試介面。軟體開發的最後階段,將透過SLIM開發工具提供的程式碼產生器(code generation tool),為一個應用程式的設定與組態,自動產生最終的應用程式執行檔,完成應用程式的開發。
SLIM為軟體開發平台,可以視為一個軟體開發工具。目的在於提供現有的嵌入式Linux軟體設計師一個更方便、更穩定、且容易使用的開發環境,並透過元件式軟體開發的流程讓軟體重用與穩定性提供更好的保障。
SLIM為一個中介軟體層(Middleware Layer),其上運行許多由軟體開發者設計之軟體模組。各模組之溝通統一由某幾個通訊協定所規範。簡單來說,此一系統簡單可以小至一個模組單獨運作,大可至多個模組連結組合而成,各司所職,提供多種功能或複雜的應用。SLIM基於的軟體開發概念即是元件導向式軟體開發,以下對其作簡單介紹。
元件導向式軟體開發(Component-based Software Development, CBSD)是 一種軟體開發的方法,主要概念是將軟體依其架構與功能性分為多個獨立元件,並在軟體開發中獨立開發該元件,其後再將所有元件組合成最終應用程式的一種軟體 方法。元件導向式軟體開發之目的在於加強軟體的可重複利用性與彈性,並提供軟體開發者一個不同於傳統開發的經驗,以期在軟體工程的角度上對於開發時間與流 程發展具有長足的進步。元件導向式概念類似現有的CORBA系統,又或類似Microsoft的COM,以及Mozilla平台上的 XPCOM等技術。元件(component)是 一個抽象概念,可以是一個獨立運行的軟體實體,或是一個必須依賴其他軟體實體才能運作的軟體。元件運行於一個軟體平台之上,該平台即是本計劃之所謂中介軟 體,提供元件運行的環境,並提供一些例如記憶體管理、連接管理、運行管理、監察管理之服務,最主要提供元件一個共用的程式設計函式庫(API),使其可以與該平台上的其他元件溝通,亦或取得作業系統(host operating system)提供的服務等。
元件導向式的軟體開發中,主要的應用程式模組皆以元件的型態為單位呈現,而各元件間的溝通管道則是連結元件、另元件間可以互相傳遞訊息、資料的媒介。各模組間之溝通,於SLIM中簡單分為資料傳輸與訊號傳達兩種,資料傳輸為大量、連續的資料溝通為主,而訊號則為小量、不連續的資料溝通為主。有關元件(components)與元件間傳輸管道(communication channels),請參閱2.4節。
歸納而言,SLIM的整體概念為模組化的設計與軟體重用,其具有靈活性、易於除錯、專注開發重點等等優點
本節說明如何取得SLIM原始碼,編譯、並開始執行。由於本系統尚未以開發原始碼的形式散佈,因此本節分為兩部份,第一部份為具有原始碼的設定、編譯與安裝,第二部份則為二進位碼發行(binary release)的設定與使用。
每個主要目錄皆附有Makefile.arm,是使用於ARM平台、使用2.95版本的toolchain所需使用的,若使用3.X或更新版本的cross-compiling toolchain,則不需使用到此版本的Makefile。
Download Source
於下載位置下載slim-1.0-src.tar.gz或slim-1.0-src.tar.bz2壓縮格式檔案後,分別解開此壓縮檔:
$> tar -zxvf slim-1.0-src.tar.gz
或
$> tar -jxvf slim-1.0-src.tar.bz2
$> cd slim
於slim/目錄下即是SLIM原始檔與各基本元件之範例原始碼。
Compilation
(注意:本說明文件中的函式庫名稱皆為debian-based的Ubuntu發行套件上的名稱,若使用其他Linux發行套件,名稱可能會有些微不同。於RPM-based的發行套件上,如Fedora Core與Mandriva,請先確定apt-get已經安裝,才可以使用本說明文件中的安裝方式。)
要開始編譯SLIM核心,需事先備齊或安裝以下套件。
libdl: 實作dynamic linking loader的函式庫。
pthread:實作POSIX thread,提供執行緒支援的函式庫。
libxml2-dev (http://xmlsoft.org/):解析XML文件的函式庫。
通常一個Linux distribution已經具有libdl與pthread了,因此只需要安裝libxml2。於一個debian為基礎的發行套件中,安裝libxml2可以由以下指令完成:
$> sudo apt-get install libxml2 libxml2-dev libxml2-utils
必須特別注意的是,若是打算作交叉編譯(cross-compiling),移植SLIM至其他系統平台上使用,則必須手動下載libxml2的原始碼並編譯成其特定平台的檔案。libxml2另外需要zlib,因此也必須交叉編譯zlib函式庫。
並由於內建元件函中,具有多個預設元件,如PCM Player與YUV Player;PCM Player利用ALSA(Advanced Linux Sound Architecture)對音效卡做控制,播放聲音;YUV Player則透過SDL(Simple DirectMedia Layer)多媒體影音函式庫對顯示卡作繪圖,來播放影片。因此若需要預設元件庫內的元件正常編譯,也需要以下函式庫:
libasound2-dev : 有關Linux音效的控制開發檔案套件
libsdl1.2-dev : 有關SDL的開發檔案l套件
libmad0、libmad0-dev:MP3元件所使用的函式庫與開發檔案套件
安裝方法如下:
$> sudo apt-get install libasound2-dev libsdl1.2-dev libmad0 libmad0-dev
另外,若你拿到的SLIM發行版本中具有jackport與jackinput兩個元件,其用來與JACK做連接的動作。JACK(Jack Audio Connection Kit)是一套音效伺服器,提供與jack連結的音效處理軟體間的low-latency溝通。有關Jack的資訊請參考附錄A。
SLIM具有jackport與jackinput兩個元件,分別負責將資料從SLIM傳送給Jack server,與從Jack server中擷取資料到SLIM端。此二元件使得SLIM完整與JACK連接,因此更可以連接到任何支援JACK的各式音效與音樂處理軟體。若需使用此兩個套件,則需要另外的套件:
jack、jackd與相關套件:JACK系統本身
libjack0.100.0-dev:JACK的development file
(optional) qjackctl:使用JACK的GUI工具
$> sudo apt-get install jack jackd libjack0.100.0-dev qjackctl
編譯SLIM的方式如下:
$> cd slim
請進入到slim根目錄下,利用make編譯:
$> make
此指令會進入slim根目錄下的slim目錄編譯SLIM核心,接著會進入components目錄,編譯所有預設的SLIM元件,接著把islim執行檔與SLIM kernel shared library檔案移到根目錄上。
也可以指令make的target,指定只編譯SLIM本身,或是只編譯元件本身:
$> make slim #編譯SLIM kernel
$> make component #編譯SLIM components
清除編譯好的資料與目的檔(object files),則使用:
$> make clean
同時,也可以指定要清除SLIM kernel或是清除元件目錄:
$> make slim_clean #清除SLIM kernel
$> make component_clean #清除SLIM components
Installation
安裝SLIM代表將SLIM kernel的共享函式庫(shared library)複製到系統函式資料夾內,並把islim這個執行檔複製到/usr/bin下。在slim/目錄下執行以下指令即可:
$> sudo make install
需要反安裝則執行以下指令:
$> sudo make uninstall
本小節說明binary release的SLIM如何安裝與使用。
Download Binrary
於下載位置下載slim-1.0.tar.gz或slim-1.0.tar.bz2壓縮格式檔案後,分別解開此壓縮檔:
$> tar -zxvf slim-1.0.tar.gz
或
$> tar -jxvf slim-1.0.tar.bz2
$> cd slim
於slim/目錄下即是SLIM二進位檔與各基本元件之範例原始碼。
Installation
安裝SLIM代表將SLIM kernel的共享函式庫(share library)複製到系統函式資料夾內,並把islim這個執行檔複製到/usr/bin下。在slim/目錄下執行以下指令即可:
$> sudo make install
需要反安裝則執行以下指令:
$> sudo make uninstall
Figure
2: Doxygen產生的SLIM
API Document
SLIM原始碼本身附有doxygen格式之注解,因此可藉由doxygen這套工具產生API Documentation,配合元件開發使用到的SLIM API。產生文件之前必須安裝doxygen,安裝方式於基於debian的系統上如下:
$> sudo apt-get install doxygen
產生API的方式:
$> doxygen doxygen_config
也可以使用slim/下的Makefile,下達
$> make doc
以上兩者皆會把產生的文件目錄放置於slim/下的doc/目錄。
要刪除文件目錄則執行:
$> make doc_clean
由doxygen產生的文件經由firefox瀏覽時大致如圖2所示,SLIM的中對於doxygen的產生格式設定為HTML。
無論是二進位發行版本,或是原始碼版本,其目錄樹結構都是相同的,差別只在於SLIM下的kernel只附有標頭檔(header files)。
SLIM的目錄結構與說明如下(可在SLIM根目錄下執行''tree -Ad''指令即可看到目錄結構):
$ROOT/ - codegen/ #程式碼產生器位置
components/ #元件原始碼
components-MG/ #元件原始碼(using MiniGUI)
project/ #使用者自行建立的目錄,通常存放project的XML檔案
repository/ #存放編譯好的元件與其介面定義XML檔案
slim/ #存放SLIM核心原始檔與標頭檔
doxygen_config #doxygen設定檔
Makefile #make使用的檔案
README #簡易使用說明檔案
使用者自行於components目錄建立自己的component資料夾後,在該資料夾開發SLIM元件,接著於SLIM根目錄下下達make component指令即可編譯元件。詳細說明請參考下節2.4關於建立元件的說明。
Figure
3: SLIM Building Blocks
SLIM下所有應用程式皆由元件與元件間的溝通管道所組成。本節依序說明如何於SLIM下撰寫一個SLIM元件,並透過溝通管道把元件連接起來,並於2.5節解釋如何利用這些連接資料建立一個應用程式專案檔,並且於2.6節說明透過islim來測試開發好的元件。SLIM中的建構元素(building blocks)可以由圖3中完整顯示。
圖3中的Component皆是同樣一個規格的元件,其中有不定數量的對外介面(interfaces or ports)。介面分為兩種,分別是傳輸資料型態的資料介面(Data Interface),與傳輸事件、訊號等資訊的事件埠(Event Ports)。兩種對外介面分別連接到同步傳輸管道(Synchronous channel)與非同步傳輸管道(Asynchronous channel)。同時,各個介面或埠,接有分是輸入端或輸出端。
以一個音樂多媒體播放器為例,傳輸播放檔案至某個播放音樂的元件時,使用的是Data Interface來連接同步的資料傳輸管道,來傳輸音樂的Raw Data(如PCM格式檔案),而控制音樂暫停、快轉等資訊,則是透過某個控制元件,經由Event Ports連接非同步的事件傳輸管道,即時控制某件事件,如對於其他元件的運作控制。
圖3中最外圈的方框包住此兩個元件,形成某個特定功能的功能性元件組合(functional composition),此一抽象概念可以進一步規範在SLIM上頭運行的元件組合,提升維護性與可讀性。
以下分別對於如何撰寫一個可運行於SLIM上的元件,以及如何使用資料傳輸通道的簡單範例,關於在SLIM上的程式設計詳細資訊,請參考第4章。
於SLIM中建立一個可重複使用的元件很簡單,基本上只需要兩個動作:
撰寫一個XML檔案:
描述該元件的對外介面(interfaces
or ports),以及某些該元件獨立具有的屬性。
撰寫元件原始檔:
建立一個屬於該元件的類別,其繼承自SMPFilter類別,並實作其中幾個成員函式(member
function)即可。
因此,以實作上來說,建立一個SLIM元件並不困難,主要難處在於設計元件的介面,並定義其所負責的工作(task)。以下分別對於步驟1與2做大概示範,並以helloworld為範例,隨後並展示如何於SLIM下執行此元件。
撰寫元件XML定義檔
一個元件必須配對有一個名稱相同的.xml檔案,描述其介面與屬性等資料。其大致格式如下所示:
<SMPFilter version=”1.0”>
<Filter name = “helloworld” version = “1.0” >
</Filter>
</SMPFilter>
該XML格式外層必須統一由SMPFilter這個標籤所起始,裏面定義一個Filter的標籤,並告知其名稱為helloworld。版本則代表這個元件的版本編號。不同版本的元件可以共存於SLIM系統之上,並由版本編號來區分。
於filter標籤內可定義兩種屬於該元件的屬性,分別是對外溝通介面與元件屬性。
以下標籤定義該元件具有一個資料類型(Data Interfaces)的對外連接埠,其必須連接一個同步的資料傳輸通道:
<OutputPort name = ”output” id = ”0”type = ”data” />
若是要定義一個非同步的資料傳輸埠(Event Ports),則把type屬性改為signal即可。若是要定義對內的連接埠,用來接收資料或事件,則標籤名稱為<InputPort>。
以下標籤則定義一個元件具有何種外部可見的設定值,稱為元件的屬性(property)。
<Property name = ”hello text” value = ”Hello World!” runtime_ro = “false”></Property>
SLIM元件的屬性是一個具有(name, value)形式的對應鍵與值,name與value分別代表屬性名稱與該屬性的值。因此每個<Property>標籤皆必須有代表該屬性的名稱(name),以及該屬性的預設值(value)。目前屬性還具有一個性質,稱為執行時期唯讀(runtime read-only, 即是runtime_ro),是定義其是否可以在該元件還在執行的期間動態去修改。譬如一個播放聲音的元件,必須於一開始設定音效卡播放的取樣頻率(sampling rate)等資訊,其資訊是在播放聲音的同時是不可以改的,否則傳送到音效卡的資訊會解讀錯誤。此時必須把runtime_ro的屬性設為true。
在此列出一個完整的SLIM元件:PCM Player的XML定義檔。該元件接收音效的raw data,把該資料傳輸至電腦上的音效裝置上,藉此播放聲音。該元件定義有一個接收資料的接收埠,其名稱為input,id為0,且具有3個執行期無法修改的屬性,分別是聲道數(number of channels),取樣頻率(sampling rate),與frame size大小(period_size)。
1 <?xml version="1.0" encoding="utf-8"?> 2 <SMPFilter version="0.1">
3 <!-- Filter Spec Here -->
4 <!-- One XML should contain only 1 filter spec -->
5 <Filter name="pcmplayer" version="1.0">
6 <InputPort name="input" id="0" />
7 <!-- Properties to export -->
8 <Property name="channel" value="2" runtime_ro="true"/>
9 <Property name="sampling_rate" value="44100" runtime_ro="true"/>
10 <Property name="period_size" value="32" runtime_ro="true"/>
11
12 </Filter>
13 </SMPFilter>
有關更詳細的元件定義XML格式,請參考第4章的詳細說明。
撰寫元件原始檔
有了元件XML描述檔後,接下去的步驟就剩下建立元件的原始檔案了。必須注意的是,在此撰寫的元件原始檔案,必須遵照已經定義好的XML屬性來做設計。譬如元件名稱必須就等於是C++原始檔案的類別(class)名稱,而其內部若使用傳輸資料相關的SLIM API,其port id的數值必須與XML定義的port id相符合。
以下示範一個簡易的元件,該元件執行其將簡單印出Hello World!資訊,即完成其任務。每個SLIM元件皆必須引用filter.h標頭檔,且一個元件以一個C++物件代表。以下為一個名為helloworld的SLIM元件標頭檔:
#include "slim/filter.h"
using namespace SMP;
class helloworld : public SMPFilter
{
public:
virtual int initialize();
virtual int process();
virtual int finalize();
};
以上標頭檔定義一個helloworld的類別,繼承自SMPFilter這個類別。即是透過繼承該類別,而使得helloworld這個類別所產生出來的物件為一個標準的SLIM元件。在helloworld中,唯一必須實作的成員函式為virtual int process(),定義該元件主要必須執行的工作。而initialize()與finalize()可以視為該元件的建構子(constructor)、解構子(destructor)對,分別處理元件初始化動作與結束前的處理動作。using namespace SMP敘述則為SLIM的namespace。
有關SLIM元件可以使用的介面請參考filter.h的API文件,以下列出基本的SLIM元件具有的共同介面:
virtual int initialize();
virtual int finalize();
virtual int process() = 0;
virtual int property_handler();
virtual int signal_handler(SMPSignal *sig);
有關SLIM元件的介面函式,相關說明留待第4章詳細解說。有關如何編譯一個元件、並組合許多元件在一起,成為一個完整應用程式的說明,請參閱2.5節。
上一小節中說明如何建立一個元件,於本節中我們進一步介紹如何在元件中使用溝通管道,與其他元件做資料或訊息的傳遞。
在SLIM中,元件與元件間沒有直接相關的屬性或軟體實體,完全必須透過SLIM核心提供的溝通管道(communication channel)來做元件間的資料交換。此一設計模式即為元件式軟體設計的主要精神。其目的在於建立一個可重複利用性高的獨立軟體元件,其定義一個良好的對外介面,所有資料交換皆會經由該溝通管道進出。
在SLIM中具有兩種資料傳輸模式,再此概要說明如下:
Synchronous Transfer: 同步資料傳輸,用於較大量、具有排程效果的資料交換。其應用如傳輸多媒體資料、字串資料等等。其特色在於具有資料緩衝的效果,且先傳輸的資料保證會先被接收。使用上可以以資料量或資料筆數為單位傳輸。是為byte-oriented或message-oriented的資料傳輸模式。
Asynchronous Transfer: 非同步資料傳輸,用於較小量、瞬間的資料傳輸,並保證在最短時間內讓對方得知此筆訊息。例如用於傳輸控制訊號、GUI事件的觸發等等。其特色為能即時通知對方,且資料並不具有緩衝效果。實際使用上只能以資料筆數為單位傳輸,而非資料量。是為message-oriented的資料傳輸模式。
以溝通管道連接兩端元件,此一動作則稱為連結或結合(binding)。一個元件式的系統即是多個元件同時運作,並具有多個binding存在於其間的組合(composition)。有關這部份請參閱下一節2.5。
在此分別列出分別對應1與2傳輸方式的SLIM API,並以簡單的兩個元件,分別做讀取檔案與寫入檔案的工作,來達成複製檔案的一個應用程式。(如同Unix下的cp指令)
Synchronous Transfer:
ssize_t smp_read(int port_id, void *buff, size_t nbytes);
ssize_t smp_write(int port_id, const void *buff, size_t nbytes);
以上兩個API函數定義於filter.h中,分別利用同步傳輸的方式,透過元件的對外連接埠port_id作讀取資料與寫出資料的動作。函式的參數相仿於C函式庫中的read()/write()函式,代表讀入或寫出nbytes bytes的資料,而寫回的資料或將要寫出的資料則存放於buff指標中。
透過smp_read()/smp_write()函式,元件將可以透過其對外定義的介面(埠)與其他任意的元件做資料的同步傳輸。資料將透過SLIM溝通管道(communication channel)的輸入端元件,被寫入溝通管道實體中的緩衝區,然後由管道的輸出端元件讀取資料。這樣的緩衝區以環型緩衝區(ring buffer)的資料結構設計,使用smp_read/smp_write的使用者將不必擔心資料緩衝的問題。且smp_read/smp_write皆具有同步化機制,確保多執行緒下的資料傳輸正確無誤,且不會具有潛在的共時性(concurency)問題。
有關同步資料傳輸的API還有另外幾組變形,請參考第4章相關說明。
Asynchronous Transfer:
int smp_signal(int port_id, SMPSignal *sig);
以上含式則是負責利用非同步資料傳輸通道,透過port_id這個非同步傳輸埠傳送一個型別為SMPSignal的指標,接收端元件則透過實作下列事件處理涵式來處理特定訊號:
virtual int signal_handler(SMPSignal *sig)
{
//implementation template, example below:
switch(sig->dest_port){
case 0:
//do something for signal coming from port id=0
break;
case 1:
//do something for signal coming from port id=1
break;
}
}
該函式在一有非同步訊號抵達時將被SLIM核心於另外一條執行緒所呼叫,並透過內部實作之switch敘述判斷由哪個非同步輸入埠來(如上面程式碼中之範例),接著做相對應的處理。必須注意的是,在process()與signal_handler()的實作中,必須注意多執行緒的同步問題,因為process()與signal_handler()必然由不同執行緒所執行。
SLIM開發工具中,並包含一個自動產生新元件目錄的Perl script工具。位於SLIM矚目錄下的compgen目錄。SLIM Component Generation Tool的用途主要是依照使用者的設定,產生初始化的SLIM元件目錄,裡面具有元件的XML定義檔、Makefile、C++標頭檔與原始檔。產生出來的原始碼是程式模版(code template),具有主要的元件介面函式宣告,與空的定義,使用者可以很快開始撰寫SLIM元件的原始碼。
SLIM Component Generation Tool簡稱compgen,執行方式為互動式(interactive)的詢問使用者相關資訊,並因而產生元件目錄。compgen具有一個起始參數,用來設定是否自動產生property_handler()的內容:
$> cd compgen
執行compgen:
$compgen> ./compgen
執行compgen,並自動產生property_handler()的內容
$compgen> ./compgen -p
自動產生property_handler()的內容會額外詢問使用者關於每一個元件屬性對應的C++類別,以便自動產生class member與property_handler()內容。compgen同時會以名稱為ENUM_開頭的enum型別,定義所有元件連接埠的名稱,並會依據是否定義非同步傳輸通道(SIGNAL_PORT)來判定是否產生signal_handler()的函式定義。詳細使用範例如下:(粗體字為使用者需輸入的部份)
$compgen> ./compgen -p
Set to generate property codes
Enter the new component name: mycomp
Enter the version: 1.0
Number of input port as DATA_PORT: 2
Data Input port[0] name:video_in
Data Input port[1] name:music_in
Number of input port as SIGNAL_PORT: 2
Signal Input port[0] name:control
Signal Input port[1] name:reserved signal
Number of output port as DATA_PORT: 1
Data Output port[0] name:encoded_data
Number of output port as SIGNAL_PORT: 2
Signal Output port[0] name:progress
Signal Output port[1] name:status_out
Number of Property: 3
Property[0] name:bit rate
Property[0] value:128
Is Property[0] runtime read-only?[y] (y/n) y
Enter C++ type of property "bit rate" (basic types of C++, pointers not allowed):unsigned short
Property[1] name:read_extended_header
Property[1] value:0
Is Property[1] runtime read-only?[y] (y/n) y
Enter C++ type of property "read_extended_header" (basic types of C++, pointers not allowed):bool
Property[2] name:algorithm
Property[2] value:scream_encoder
Is Property[2] runtime read-only?[y] (y/n) y
Enter C++ type of property "algorithm" (basic types of C++, pointers not allowed):string
Creating XML file mycomp.xml...done
Creating Makefile.pthread...done
Creating source file mycomp.h ...done
Creating source file mycomp.cpp ...done
$compgen>
以上範例主要是產生一個名為mycomp的元件,其中具有2個data input port、2個signal input port、1個data output port、以及2個signal output port。另外具有3個元件屬性,分別是bit rate、read_extended_header、algorithm三樣,並詢問相關port的名稱、屬性名稱、預設值,以及若-p選項打開時,會詢問property對應的C++型別。目前只支援單一型別,如bool, string, int, long, float, double等,並不支援pointer、array等類型。產生出來的元件放置於compgen目錄下的filter_mycomp下,其中具有下列4個檔案:
Makefile.pthread : mycomp元件的預設Makefile
mycomp.xml:mycomp元件的介面定義檔,包含輸出入埠定義,以及元件屬性
mycomp.h:mycomp元件的C++標頭檔,包含各port的enum與元件介面函式宣告
mycomp.cpp:mycomp元件的C++原始碼檔,包含元件介面函式的空定義、以及為了共享函式庫動態載入與卸載相關的定義函式,與property_handler()中自動產生的程式碼。
以下列出相關產生出來的檔案的重要部份,並依序做介紹:
Makefile.pthread:
5 #C++ compiler
6 CXX = g++
7
8 #Compiling arguments
9 CFLAGS = -g -DUSE_PTHREAD -DX86_LINUX -I../../
10
11 #Linking arguments
12 LFLAGS =
13
14 #filter name
15 FILTER = mycomp
第9, 12行是定義GCC編譯器的參數與LD的參數,若元件使用到其餘的library,請自行於這兩行加入相關設定參數。第15行是定義本元件的名稱。
mycomp.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- SLIM Component "mycomp" Interface Definition XML -->
3 <!-- Auto generated by SLIM Component Template -->
4
5 <SMPFilter version="1.0">
6 <!-- Filter Spec Here -->
7 <!-- One XML should contain only 1 filter spec -->
8 <Filter name="mycomp" version="1.0">
9 <!-- Input Ports -->
10 <InputPort name="video_in" type="default" id="0" />
11 <InputPort name="music_in" type="default" id="1" />
12 <InputPort name="control" type="signal" id="0" />
13 <InputPort name="reserved signal" type="signal" id="1" />
14
15 <!-- Output Ports -->
16 <OutputPort name="encoded_data" type="default" id="0" />
17 <OutputPort name="progress" type="signal" id="0" />
18 <OutputPort name="status_out" type="signal" id="1" />
19
20 <!-- Properties -->
21 <Property name="bit rate" value="128" runtime_ro="true" />
22 <Property name="read_extended_header" value="0" runtime_ro="true" />
23 <Property name="algorithm" value="scream_encoder" runtime_ro="true" />
24
25 </Filter>
26 </SMPFilter>
27
其中第10-13行為Input port的相關定義,16-18為Output port,21-23為Property的定義,皆為自動產生,使用者可以完全不必修改XML檔案即可正常使用,除非開發該元件時需額外新增或刪除元件埠,或修改屬性的預設值。'
mycomp.h
...
36 private:
37 // Ports enumerations defined
38 //Data input ports
39 enum ENUM_DATA_INPORT_MYCOMP {
40 _DATA_INPORT_video_in,
41 _DATA_INPORT_music_in,
42 };
43 //Signal input ports
44 enum ENUM_SIG_INPORT_MYCOMP {
45 _SIG_INPORT_control,
46 _SIG_INPORT_reserved_signal,
47 };
48 //Data output ports
49 enum ENUM_DATA_OUTPORT_MYCOMP {
50 _DATA_OUTPORT_encoded_data,
51 };
52 //Signal output ports
53 enum ENUM_SIG_OUTPORT_MYCOMP {
54 _SIG_OUTPORT_progress,
55 _SIG_OUTPORT_status_out,
56 };
57
58 // Auto generated component properties as class members
59 //property bit rate
60 unsigned short _prop_bit_rate;
61 //property read_extended_header
62 bool _prop_read_extended_header;
63 //property algorithm
64 string _prop_algorithm;
...
89 //component signal handler function
90 virtual int signal_handler(SMPSignal *sig);
91
其中39-56行為自動產生的元件埠enum類別,分別代表每一個定義的連接埠的ID。使用者將可以使用這個名稱,而不必在意底層該連接埠的真實ID是多少。譬如需使用reserved signal這個signal input port時,只需使用_SIG_INPORT_reserved_signal即可。注意,若埠的名稱有空格,compgen會自動於產生的C++中填入底線(_)符號。第59-64則為compgen -p選項打開後自動產生的部份,compgen將會為每個元件屬性定義一個class member。如read_extended_header這個屬性,我們設定其為bool的C++型別,將會產生一個型別為bool,名稱為_prop_開頭的_prop_read_extended_header變數。第90行則為自動宣告signal_handler,因為mycomp具有signal類別的input連接埠。
mycomp.cpp
...
44 /*!
45 * SLIM Component Main Thread Block
46 */
47 int mycomp::process()
48 {
49 //
50 // The main works done in this component should be put here
51 // Note: This member function acts as a thread in SLIM kernel
52 //
53
54 //default main loop
55 for(; !exit_check();){
56 //
57 // [add your own codes here]
58 //
59 }
60
61 return 0;
62 }
...
CPP檔案中,會自動為該元件的process()填入如第55至59行的main loop,因為process()這個member function會被SLIM當作是一個thread function,以執行緒的方式去執行。使用者需於這個main loop中定義該元件的主要程式碼。
66 /*!
67 * SLIM Component Property Update Block
68 * (called when a property of the component changes)
69 */
70 int mycomp::property_handler()
71 {
72 //
73 // [add your codes to import property from XML into class member]
74 //
75
76 // Example:
77 // //for type: int, short, long, bool, float, double, char ...
78 // get_property("property_name", common_value);
79 //
80 // //for type: string
81 // string_value = get_property("property_name");
82 //
83
84 // Auto generated codes to read component properties into class members
85 //property bit rate
86 get_property("bit rate", _prop_bit_rate);
87 //property read_extended_header
88 get_property("read_extended_header", _prop_read_extended_header);
89 //property algorithm
90 _prop_algorithm = get_property("algorithm");
91 return 0;
92 }
...
compgen打開-p選項後,產生的CPP檔案中將會具有如第85-90行的程式碼,自動透過get_property這個API將XML中或經由使用者於執行時期動態改變而成的新屬性讀回class member中。這些class member於header中定義為_prop_開頭的變數。
...
97 /*!
98 * SLIM Component Signal Handler Block
99 */
100 int mycomp::signal_handler(SMPSignal *sig)
101 {
102 //
103 // [add your own signal handling codes here]
104 //
105
106 //default handling routines
107 switch(sig->dest_port){
108 //signal comes from port 0 (port name = control)
109 case _SIG_INPORT_control: // Port ID = 0
110 // handling routines for signal input port 0 here
111 //
112 break;
113 //signal comes from port 1 (port name = reserved signal)
114 case _SIG_INPORT_reserved_signal: // Port ID = 1
115 // handling routines for signal input port 1 here
116 //
117 break;
118 default:
119 fprintf(stderr, "[Component:mycomp]: Received signal from undefined port id = %d\n", sig->dest_port);
120 return -1;
121 }
122
123 return 0;
124 }
...
compgen產生的signal_handler定義中,將會具有如第107行的switch敘述。該敘述為了分辨收到的事件是從哪一個非同步事件輸入埠來到該元件的,如109, 104這邊定義的,mycomp元件具有兩個非同步事件輸入埠,compgen會自動產生兩個case敘述,使用者可以很方便填入相關的處理程式碼於這個switch敘述中。
以上簡介compgen的使用方式,並簡介產生出來的component template,方便SLIM component開發者快速開發元件。
SLIM上的應用程式主要由兩部份所形成:SLIM元件與元件連結(binding)。SLIM同樣採用XML標籤式語言來描述一個應用程式所需的構成元件與其間的連結資訊。另外,也可以同時設定各元件的屬性與SLIM核心的部份參數。
一個定義SLIM應用程式的XML描述檔必須使用以下標籤起始:
<SMPProject SMPversion="1.0" name="project_name">
</SMPProject>
其中SMPversion定義支援的SLIM版本,而name則為該專案的專案名稱。在SMPProject標籤內則是可以定義任何元件與溝通管道的組合與連結。
定義元件的用法如下:
<Filter name = "component_name" version = "1.0" id = "0">
<item name = "property_name_1" value = "value_1" />
<item name = "property_name_2" value = "value_2" />
</Filter>
<Filter>標籤指定元件的名稱,該名稱必須符合在C++該元件的類別名稱,版本編號則是使用到的元件版本,而id則為該元件的唯一ID值,從0開始,在同一個專案內不可以重複。<Filter>標籤內並可以定義該元件支援的屬性的自訂值,屬性為一個(name, value)的對(pair),指定方式使用<item>標籤定義。
定義溝通管道的用法如下:
<Buffer from = "0:0" to = "1:0,2:1,3:0" type = "default" maxsize = "65536" />
<Buffer from = "0:0" to = "1:0" type = "signal" />
第一行為定義一個型別為Data(同步傳輸通道)的傳輸通道,其內部緩衝區有65536個位元組,其連結該專案檔內的元件0的第0個output port,接到元件1的0號input、元件2的1號input,與元件3的0號input port。
第二行則為Signal類型的非同步資料傳輸通道,連結元件0的0號output port與元件1的0號input port。沒有maxsize屬性的設定。
例如一個播放MP3的SLIM應用程式專案檔,其XML為:
1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- This File is generated by SMP -->
3 <SMPProject SMPversion="0.1" name="MP3">
4 <Group id="0">
5 <Filter name="freader" version="2.0" id="0">
6 <item name="buffer_size" value="65536" />
7 <item name="filename" value="" />
8 </Filter>
9 <Filter name="pcmplayer" version="1.0" id="1">
10 <item name="channel" value="2" />
11 <item name="period_size" value="32" />
12 <item name="sampling_rate" value="44100" />
13 </Filter>
14 <Filter name="mp3decoder" version="1.0" id="2">
15 </Filter>
16 </Group>
17 <Buffer from="0:0" to="2:0" type="default" maxsize="40960" />
18 <Buffer from="2:0" to="1:0" type="default" maxsize="40960" />
19 </SMPProject>
islim (interactive shell of SLIM)是一個類似shell的環境,使用者可以下任何支援的指令來對SLIM核心或其上層的應用程式作控制與測試。以下分為執行與使用兩個部份作簡單介紹。
Execution of islim
islim對應於SLIM根目錄下的islim執行檔。islim在執行期將載入libsmpkernel這個共享函式庫,因此執行方式有以下兩種:
透過make install將libsmpkernel安裝於系統共享函式庫中,使得islim可以使用:
$> sudo make install
$> islim
或是不透過make install的方式,於SLIM根目錄中指定LD_LIBRARY_PATH環境變數,告知islim搜尋共享函式庫的位置:
$> LD_LIBRARY_PATH=. ./islim
或使用:
$> export LD_LIBRARY_PATH=.
之後於此console下執行islim將可以直接使用:
$> ./islim
即可。
islim指令的參數可透過以下指令得知:
$> islim -h
Interactive Shell of SLIM (SCREAM LInux Middleware)
islim -[hvrp] [arguments]
-h this help
-v print the version
-r [repository path] set the repository path
-p [project XML file] load the project file
其中-r與-p兩個參數經常使用;-r用於指定預設的元件庫放置的目錄。若無指定,則預設為目前所在的位置(./)。-p參數用於一開啟islim便載入所需執行的project XML檔案,即是2.5介紹的SLIM應用程式專案檔,是一個XML格式的文字檔。
如以下指定:
$> islim -r repository -p project/mp3_player.xml
其代表:設定目前目錄下的repository目錄為元件庫目錄,在此目錄將具有所需的元件共享含式庫與各元件的XML定義檔。並於一開啟islim時即載入位於project/的mp3_player.xml專案檔案,並進入islim的shell環境。
Usage of islim
islim使用方式可以由islim shell下以help取得:
SMP:#> help
Available commands:
( command arguments notation: "|" OR, "<>" an optional, "[]" a must-have )
SMP Execution Control:
start // start SMP execution
*pause // pause SMP execution
*resume // resume SMP execution from suspended state
stop // stop SMP execution
quit | bye // exit SMP
---------------------------------------------------------------
Project Manipulation:
load <project_XML>
// load project XML from path = project_XML
lsa all // load all available filters and mark them with an ID
lsa f <fid> // Filter Info: display filter's information of filter ID = fid,
which is the id assigned by command "lsa all"
If fid not specified, show all filters' info
add f [fid] // add filter by ID = fid, which is the id assigned by command "lsa all"
add b [SRC] [DEST] <SIZE>
// add buffer with source = SRC, destination = DEST, and optionally maxsize = SIZE
SRC is in the format: [filter_id]:[port_id], ex: 0:1
DEST is in the format: [filter_id]:[port_id],[filter_id]:[port_id],... , ex: 1:0,2:1
example: add b 0:0 1:0,2:0 65536
add s [SRC] [DEST] //Same as add b except that this is for adding a signal buffer
rm f [fid] // delete filter by ID = fid
rm b [bid] // delete buffer by ID = bid
clear project
// clear everything in the current project.
Will clean filter and buffer information.
save <project_filename>
// save project XML file to file = project_filename
---------------------------------------------------------------
Settings:
which repos // display current repository path
set repos [path_of_repos]
// set the repository path
set b // display buffer Read/Write information
set nob // do not display buffer Read/Write information
set f [fid]:[property_name]=[value]
// set property = property_name with new value = value, of filter with ID = fid
// NOTE: there should be no spaces between '=' and the property_name or value
reset f <fid>
// reset property to default values of filter ID = fid
If fid not specified, reset all filters' property
set rt // set to start SMP kernel in SCHED_FIFO realtime scheduling method
set nort
// set to start SMP kernel in SCHED_OTHER normal scheduling method (default)
set wd //set to start SMP kernel with watchdog
set nowd //set to start SMP kernel without watchdog
set swd //set to start SMP kernel with signal watchdog
set noswd //set to start SMP kernel without signal watchdog
*set prio [fid] [priority]
// set priority of the thread of filter ID = fid, to the value = priority
---------------------------------------------------------------
Project Information:
ls | info // display current project information
stat b <bid> // Buffer Status: display buffer's information of buffer ID = bid
If bid not specified, show all buffers' info
ls b <fid> // Buffer Info: display buffer's information of buffer ID = bid
If bid not specified, show all buffers' info
ls f <fid> // Filter Info: display filter's information of filter ID = fid
If fid not specified, show all filters' info
*ls t <fid> // Thread Info: display thread's information of filter ID = fid
If fid not specified, show all threads' info
---------------------------------------------------------------
SMP Interpreter:
history <no>// if history number = no is not specified, display last 10 commands
if <no> is given, execute the command.
server // working as a server. remote SMP controller client will take control
of current smp program, and will return control while remote client
execute "quit" command
help // this text
*: Not supported in this version.
以上文字為help顯示的資訊。較為重要常用的以紅色標示出,分別為以下指令:
start, stop, quit,
lsa all, add f, add b, add s, rm f, rm b,
ls, ls f, ls b, help
以下說明使用方式,並依需要以實際例子作為說明。其他指定請參考3.1節說明。
SLIM應用程式執行流程控制
start : 執行已載入的專案(SLIM應用程式)
stop : 停止在正執行的專案(SLIM應用程式)
quit : 結束islim,並結束正在執行的專案(SLIM應用程式)
SLIM應用程式載入與連結(composition)
lsa all : 於元件庫中讀取並列出所有支援的SLIM元件
add f [fid] : 加入某元件,以lsa all列出的ID數字為fid加入
add b [SRC] [DEST] <SIZE> : 於元件間連結一條同步資料傳輸通道
SRC與DEST以''filter ID : port ID''的格式指定資料傳輸來源與目的
SIZE為optional參數,可以指定這條資料通道的預設最大大小為多少bytes
例如由元件ID=1的第0號Output Port連接到元件ID=2的第2號Input Port,預設大小為1024 bytes:
SMP$> add b 1:0 2:2 1024
add s [SRC] [DEST] : 於元件間連結一條非同步資料傳輸通道
SRC與DEST的指定方式如同add b指定所示
rm f [fid] : 刪除已加入使用列表的某元件,以及連結到該元件上所有的傳輸通道, 以ls指令所見之fid數字指定之
rm b [bid] : 刪除已加入使用列表的某傳輸通道,以ls指令所見之bid數字指定之。 注意,不管要移除同步或非同步的傳輸通道,皆使用rm b指令。
SLIM應用程式資訊顯示
ls : 列出目前加入islim執行列表的元件與資料通道連結資訊(composition)
ls f : 列出加入的元件的詳細資訊,包含其對外介面、屬性與設定值、ID等訊息
ls b : 列出加入的資料通道的資訊,包含其類別(Data or Signal,同步或非同步)、
緩衝區大小、連結到哪些元件等資訊
help : 顯示說明文件,即時查閱指令使用方式
實際範例說明
以上簡要說明islim的使用方式,以下並列出一個實際範例,指示如何利用islim,於預設元件庫中加入3個預設的元件,建立一個MP3播放器,並加入兩個資料通道連接此3個元件,並執行之:(粗體字為實際輸入之指令)
$> ./islim -r repository/
Loading repository from repository/
SMP#> lsa all
Available Filters in The System:
=================================
[ 0]: cmdwrapper version: 1.0
[ 1]: freader version: 2.0
[ 2]: fwriter version: 1.0
[ 3]: hello version: 2.0
[ 4]: jackinput version: 1.0
[ 5]: jackplayer version: 1.0
[ 6]: jackport version: 1.0
[ 7]: mp3decoder version: 1.0
[ 8]: mycomp version: 1.0
[ 9]: pcmplayer version: 1.0
[10]: printer version: 1.0
[11]: single version: 1.0
[12]: timer version: 1.0
[13]: yuvplayer version: 1.0
SMP#> add f 1
[SMPInterp]: Filter 1 Successfully Added.
SMP#> add f 7
[SMPInterp]: Filter 7 Successfully Added.
SMP#> add f 9
[SMPInterp]: Filter 9 Successfully Added.
SMP#> add b 0:0 1:0
[SMPInterp]: Buffer added!
SMP#> add b 1:0 2:0
[SMPInterp]: Buffer added!
SMP#> ls
SMP Kernel version 1.0
=====================================================================
Filter[ 0]: none (freader - version: 2.0) Input: 0, Output: 1
Filter[ 1]: none (mp3decoder - version: 1.0) Input: 1, Output: 1
Filter[ 2]: none (pcmplayer - version: 1.0) Input: 1, Output: 0
---------------------------------------------------------------------
Buffer[ 0]: Size = 1024 From Filter [ 0] to [ 1]
Buffer[ 1]: Size = 1024 From Filter [ 1] to [ 2]
---------------------------------------------------------------------
Total 3 filter(s) and 2 buffer(s) loaded.
SMP#> start
[freader]: Enter the filename: ../res/test.mp3
[SMP]: kernel started!
...
以上動作即可以由../res/test.mp3檔案播放MP3音樂。上述的步驟即為元件式軟體開發的元件連結組合(composition)階段。透過連接各個元件,指定資料流向等等,將可以使多個元件合作運作起來。islim即為提供composition與execution的工具,作為使用者開發SLIM應用程式的測試、除錯工具之一。並可以透過save等指令,將設定值寫入XML專案檔,透過codegen工具,建立該專案的C++ source檔案,再利用make建立一個跟平常無異的應用程式執行檔。下節即說明這部份的實際操作方式。
上節我們實際透過islim建立一個MP3播放器,本節我們將展示如何利用islim將該專案儲存成project的XML描述檔,接著透過SLIM codegen Tool將其轉換為C++原始檔,經由make作編譯後,形成一個與平常無異的應用程式執行檔。唯一差別只有該執行檔將會於執行期連結libsmpkernel共享含式庫,利用SLIM runtime來執行。
要使用SLIM codegen Tool,必須安裝有perl工具,以及一個額外的CPAN(Comprehensive Perl Archive Network) perl模組:XML::Simple。可以利用CPAN的自動下載功能安裝:
$> perl -MCPAN -e shell
...
cpan> install XML::Simple
然後按照問題指示打上yes即可安裝使用XML::Simple模組。
接續上節範例,將該MP3應用程式儲存成XML檔案,我們可以利用islim的save指令:
SMP#> save
[SMPParser]: Enter Project Filename:myProject.xml
[SMPParser]: Enter Project Name:MP3Player
即可建立一個專案名稱為MP3Player的myProject.xml專案檔。當然使用者也可以透過2.5節所示,自己編輯一個SLIM Project的XML檔案。
接著進入SLIM根目錄下的codegen目錄,執行gen.pl這個Perl的程式,將可以依照該專案XML檔案建立一個C++原始檔,此檔案編譯後將可以獨立執行,不需依靠islim:
SMP#> bye
[SMPInterp]:Quitting SMP...
[SMPInterp]:Quit
[SMP]:Kernel destructed!
$> cd codegen/
$codegen> ./gen.pl ../myProject.xml
SLIM Codegen Tool (version 0.1)
========================================
Previous *.cpp exists, make clean ...
Enter output C++ filename: mp3player
Enter SLIM component repository path: [default: "../repository"]:
Repository set to ../repository/
[sampling_rate]=44100
[channel]=2
[period_size]=32
Filter : pcmplayer id=1, cpp_id=0, version=
Filter : mp3decoder id=2, cpp_id=1, version=
[filename]=
[buffer_size]=65536
Filter : freader id=0, cpp_id=2, version=2.0
buffer from=0:0 to=2:0 type=default size=40960
buffer from=2:0 to=1:0 type=default size=40960
========================================
SLIM Codegen Tool successfully created source file : mp3player.cpp
Next Step: type "make" to create executable,
type "make app" to create release directory
$codegen>
接著將會在codegen目錄下產生一個名為mp3player.cpp的原始檔。在同樣的目錄執行make,將可以產生一個名為test的執行檔,並透過make app,將可以把所需的元件共享函式庫、XML定義、與SLIM核心的libsmpkernel.so檔案複製到release資料夾,並將應用程式執行檔更名為slimAPP,完成應用程式開發。
必須注意一點,使用codegen功能之前,必須於SLIM主目錄執行過make以後才可以正常使用。
以下展示實際使用方式:
$codegen> make
$codegen> make app
$codegen> cd release/
$codegen/release> ./slimAPP
產生的release資料夾將可以獨自運行,惟獨必須注意LD_LIBRARY_PATH的問題,若在該台主機上尚未於SLIM主目錄執行make install,則執行slimAPP執行檔必須用以下方式:
$codegen/release> LD_LIBRARY_PATH=. ./slimAPP
詳細方式請參考2.6節關於LD_LIBRARY_PATH的說明。
本節完整介紹islim的使用方式,並對於各個指令的使用詳加介紹。以下5小節將完整指令分為5個部份,分別為SLIM系統設定(SLIM System Configuration)、應用程式執行控制(Execution Control)、應用程式專案管理(Project Manipulation)、訊息顯示與狀態查尋(Information Display and Status Querying)、其他(Others)等項目。下表顯示各類別的支援指令:
Category |
Commands of islim |
SLIM系統設定 |
which repos, set repos, set b, set nob, set rt, set nort, set wd, set nowd, set swd, set noswd, *set prio |
應用程式執行控制 |
start, *pause, *resume, stop, quit, bye |
應用程式專案管理 |
load, lsa all, lsa f, add f, add b, add s, rm f, rm b, clear project, save, set f |
訊息顯示與狀態查詢 |
ls, info, stat b, ls b, ls f, *ls t |
其他 |
history, help |
* : 目前版本尚未支援
由於SLIM一開始使用不同的執行緒函式庫,因此其中部份指令移植至現今的環境尚未支援,或未繼續維護測試,由*符號注解。由於版本尚未支援,於本文件中不予介紹與說明,待該指令完成或成熟後,將在本文件更新版本中依序加入。
本小節介紹有關設定SLIM核心運作模式、屬性等資訊的幾個指令,列出如下:
which repos, set repos,
set b, set nob,
set rt, set nort,
set wd, set nowd,
set swd, set noswd
分別予以介紹如下:
which repos : 列出目前元件庫的設定位置。若執行islim時未指定-r參數,則預設為./目錄(當前目錄)。
set repos [path_of_repository] : 設定元件庫位置為path_of_repository。該字串必須為唯一目錄,可以是相對目錄,如''repository/'',或是系統上的絕對目錄,如:''/usr/local/slim_repository''。
set b : 顯示元件間的資料傳輸通道(限同步傳輸管道)的即時傳輸狀態。其格式如以下範例:
Buf[1] R( 3760): w_flag = 34480, r_flag = 38240, used = 37200/ 40960 (90.8%)
Buf[1] R( 3760): w_flag = 38240, r_flag = 1040, used = 37200/ 40960 (90.8%)
Buf[1] W( 8192): w_flag = 0, r_flag = 1040, used = 39920/ 40960 (97.5%)
Buf[1] R( 3760): w_flag = 1040, r_flag = 4800, used = 37200/ 40960 (90.8%)
其中Buf後接的中括號中代表同步資料傳輸通道的ID,接下去的字元R代表對該傳輸通道作讀取動作,小括號內則代表讀取的位元數。W則代表寫入該傳輸通道。w_flag、r_flag則代表在同步資料傳輸通道的系統實作上的環型緩衝區(Ring Buffer)目前的寫入旗標與讀取旗標的當前位置。used則代表該傳輸通道內的緩衝區使用了多少位元組,並具有使用率的資訊。
由於顯示即時傳輸狀態通常必須於標準輸出(standard output)不停頻繁寫入資料,效能因此會低落,CPU使用率提升。因此預設是關閉的。只有需要檢查系統是否運作,或除錯時才需要打開。
set nob : 關閉顯示即時傳輸狀態。
set rt : 將SLIM執行的應用程式優先權提升至Linux下的即時排程優先權。在SLIM下,每個應用程式的組成皆由SLIM主要的行程分為內部的多個執行緒去執行,set rt指令設定SLIM核心啟動各個元件,產生執行緒時,是用Linux下的即時排程權限(realtime scheduling priority)執行。取得即時優先權必須具有root權限。否則SLIM執行時會出現RT錯誤訊息,SLIM應用程式並以普通優先權繼續執行。
另外必須注意,使用set rt後,必須等到下次啟動(start),變更才會生效。
set nort : 關閉應用程式即時排程優先權。
set wd : SLIM預設在啟動每個元件時,會在內部的看門狗子系統(watchdog)登記一個要求監看的旗標。若元件的主要成員函式process()超過特定秒數沒有動作(沒有跳離主要回圈,請參考第4章關於元件programming的設計模式),watchdog將會判斷該元件執行失敗或不正常,而中止該應用程式執行。set wd則是開啟此功能的指令。
set nowd : 關閉SLIM的watchdog監看功能,可以少一些SLIM核心額外計算量。
set swd : SLIM預設在啟動每個元件時,若該元件定義有signal_handler(),即是具有非同步資料接收埠的存在時,會自動啟用該事件處理函式的監看執行緒,此功能為SLIM的事件處理看門狗(Signal watchdog)功能。若該事件處理函式超過一定時間未結束,將可能影響後續的事件處理動作,signal watchdog將會認為該元件不正常執行,而中止該應用程式執行。set swd則是開啟此功能的指令。
set noswd : 關閉SLIM的signal watchdog監看功能,可以少相對多一些的SLIM核心記憶體與計算量。
本節說明有關islim中控制應用程式執行的幾個指令,列出如下:
start, stop, quit, bye
*pause, *resume
分別予以介紹如下:
start : 開始執行已載入的應用程式,已載入的應用程式(元件組合)可以透過ls指令察看。若目前沒有任何元件,則不動作。start的內部實作將會執行各元件的initialize()函式,當所有元件的initialize()皆成功執行完畢後,接著核心將各元件中的process()以一個獨立的執行緒開始執行。
stop : 停止執行已載入的應用程式。此動作將會重設目前的執行狀態,並消除所有的元件執行緒。stop的內部實作將會執行各元件的finalize()函式。
quit , byte : 結束islim,回到系統shell。
*pause : 暫停各元件的執行,並隨後依序呼叫各元件的pause()函式。內部實作是將各元件之process()執行緒暫停。在目前的SLIM版本尚未支援。
*resume : 若元件是暫停狀態,先依序呼叫各元件的resume()函式後,重新開始各元件的執行。內部實作是將各process()執行緒由暫停的狀態回復。在目前的SLIM版本尚未支援。
本小節說明有關SLIM應用程式的連結與設定(composition and setup)的islim指令,其中包含如何建立一個應用程式、儲存應用程式專案檔,修改元件屬性等等有關SLIM應用程式的處理指令。所介紹的指令如下:
load, save, clear project
lsa all, lsa f,
add f, add b, add s,
rm f, rm b,
set f
分別予以介紹如下:
load <project XML> : 讀取SLIM應用程式專案XML檔案。作用跟islim的-p參數相同。可以利用現有的XML描述檔來加入元件與傳通通道,並做元件屬性的設定、SLIM 核心(runtime部份)的設定等等,如3.1.1節所示。
save : 將現有的元件組合儲存為XML檔案。目前尚未支援的功能為SLIM核心設定的部份,未能寫回XML檔案。
clear project : 將現有載入的元件組合全部刪除,包含所有元件與資料傳輸通道。
lsa all : 從元件庫目錄中讀取所有的元件XML定義,並列出可以使用的元件名稱、版本資訊,並做編號。往後利用add f指令加入元件的時候,其ID即是此列表中的編號。
lsa f <ID>: 從元件庫目錄中讀取所有元件的XML定義,並列出特定ID的元件詳細資訊。其中包含:元件名稱、版本資訊、各個對外連接埠類型與名稱、連接埠ID、各個屬性名稱、各個屬性其預設值,以及屬性的執行期唯獨設定。若不加ID參數時,列出所有可用的元件。
add f [ID] : 加入id為ID的元件於islim中
add b [SRC] [DEST] <Size> : 加入一同步資料傳輸通道,其來源端元件為SRC,目的端元件為DEST,可指定Size值,為資料傳輸通道的緩衝區大小,單位為bytes。若不加Size資訊,預設大小為1024 bytes。
SRC與DEST的格式為[fid]:[pid],前者為元件ID,後者為該元件中的連接埠ID,兩者間以分號(:)格開,不許有空白。
其中必須注意,這裡的元件ID為ls指令看到的元件ID,而非lsa all指令看到的。因此在執行add b指令之前,通常必須已經加入該溝通管道兩端的所有元件了。一條SLIM上的資料傳輸管道皆為一對一或一對多,若為一對多的情形,請多次使用add b指令連接一對多的傳輸通道。
add s [SRC] [DEST] : 加入一非同步資料傳輸通道,其來源端元件為SRC,目的端元件為DEST,沒有Size欄位。SRC與DEST的格式如add b指定所述相同。
rm f [ID] : 於islim中刪除某個已經加入的元件,其id為ID。此ID同樣是由ls指令中的元件id。
rm b [ID] : 於islim中刪除某個已經加入的資料傳輸通道。為add b/add s的相反指定。其ID值為ls指令中的同步資料傳輸通道id。在islim中,不管型別是同步或非同步的資料傳輸通道,其ID值皆是從0累加,即是每個傳輸通道不管型別為何,ID值都是單一不重複(unique)的。因此沒有rm s指令。
set f [ID]:[property_name]=[value] : 設定某ID元件中的屬性,其將要設定的屬性名稱為property_name,其屬性值為value。本指令必須注意ID與property_name之間的分號(:)間不可以有間格,而property_name與value間的等號(=)間同樣也不可以有間隔。若該屬性不被id為ID的元件所擁有,則本指令無作用。value的型態在內部皆以string型別儲存,因此可以指定具有空白字元的value值。如設定一元件ID=3的屬性sampling_rate為44100,則指令用法如下:
SMP#> set f 3:sampling_rate=44100
本小節說明有關islim上關於執行狀態查詢與專案查詢、元件查詢、傳輸通道查詢的指令。包含以下部份:
ls, info,
stat b, ls b, ls f,
分別予以介紹如下:
ls , info : 顯示目前加入islim的專案概要設定,其顯示內容包含SLIM核心版本、各個元件與其ID、各元件的別名、名稱、版本與對外介面輸入與輸出端的個數、以及各傳輸通道的類別(同步或非同步)、與連接元件的資訊。ls通常用來查找某元件的ID值,並給使用者一個快速得知目前載入的專案的一個方便指令。以一個MP3播放器為例,ls呈現出來的訊息如下:
SMP#> ls
SMP Kernel version 1.0
=====================================================================
Filter[ 0]: none (freader - version: 2.0) Input: 0, Output: 1
Filter[ 1]: none (pcmplayer - version: 1.0) Input: 1, Output: 0
Filter[ 2]: none (mp3decoder - version: 1.0) Input: 1, Output: 1
---------------------------------------------------------------------
Buffer[ 0]: Size = 40960 From Filter [ 0] to [ 2]
Buffer[ 1]: Size = 40960 From Filter [ 2] to [ 1]
---------------------------------------------------------------------
Total 3 filter(s) and 2 buffer(s) loaded.
其中Buffer代表傳輸通道,而若出現Size=字樣,則代表同步資料傳輸通道,若出現<Signal>字樣,則代表非同步傳輸通道。
stat b <bid>: 在執行期間才有功能的一個指令。其顯示某特定同步資料傳輸通道的狀態,若沒有指定bid,則列出該應用程式所有同步資料傳輸通道的資訊。其資訊顯示如以下範例:
SMP#> stat b
Current Number of Buffers: 2
Buf[0] STATUS: w_flag = 33058, r_flag = -1, used = 40960/ 40960 (100.0%)
Buf[1] STATUS: w_flag = 2480, r_flag = -1, used = 40960/ 40960 (100.0%)
其資訊內容相等於set b指令所看到的資料,stat b不同之處在於只顯示當時執行的瞬間其同步資料傳輸通道的內資訊。
ls b <bid> : 列出某資料傳輸通道ID=bid的詳細資訊,若bid沒有指定,則列出目前載入的所有資料傳輸通道的詳細資訊。其產生的訊息如下範例所示:
SMP#> ls b 0
Data Buffer[0] Number of Destinations: 1
====================================================
Size: 40960 bytes
Source Filter Id: 0
Source Filter Port Id: 0
Destination Filter Id: 2, Port Id: 0
其內容包含其類型、是否是一對一還是一對X的連結方式、大小(限同步資料通道)、來源端元件ID、來源端元件之連接埠ID,與目的端元件ID、目的端元件之連接埠ID。
ls f <fid> : 列出某元件ID=fid的詳細資訊,若fid沒有指定,則列出目前載入的所有元件詳細資訊。其產生的訊息如下範例所示:
SMP#> ls f 0
Filter Name = freader Version:2.0
Port Name Port ID
-------------------------------------------
Outport: output 0
Property Name Property Value Runtime Attribute
---------------------------------------------------------------
buffer_size 65536 Read Only
filename Read Only
其中包含所有定義於元件XML的資料,以及目前的屬性(property)設定值。
本小節說明有關islim上其他無關於SLIM本身的其他指令。包含以下兩者:
history, help
分別予以介紹如下:
history <command number> : 顯示最近幾次的指令列表,並編號。若是command number有值,則等同於執行該最近執行過的指令,其用意與Unix系統下的history指令相仿。
help : 顯示說明文件,該文件如2.6節所示,提供islim使用者即時的查詢指令使用方式,並得以了解並利用。
Eclipse Plugin為SLIM的開發工具組架設的方式,以一個Eclipse擴充套件的方式提供SLIM上的軟體開發者於Eclipse整合開發環境下從設計元件介面(component XML)、撰寫元件原始碼(programming SLIM components)、元件編譯(component compilation)、SLIM應用程式連結組合(composition)、到圖型化的控制、執行、設定工具(islim GUI版本)。
SLIM的Eclipse plugin目前正在開發階段,將會整合compgen, islim, codegen等三個工具,並預計於2007年年中將會有初步版本釋出。因此本說明文件之SLIM版本尚未支援Eclipse Plugin,此節內容於本說明文件之未來版本將依序填滿。
無資料。
無資料。
無資料。
4.0 SOFTWARE DEVELOPMENT ON SLIM
本節介紹SLIM系統內部架構,以及於SLIM系統上的軟體開發概要與流程。分別先介紹SLIM系統上的開發所根基的元件式軟體開發(Component-based Software Development, CBSD)(4.1.1),介紹CBSD的概念與目前發展,接著簡介SLIM系統架構(4.1.2),讓SLIM上的開發者瞭解SLIM內部運作概念,最後介紹於SLIM上的軟體開發流程(4.1.3),以及其對應到的階段與步驟,提供完整的軟體開發整合平台。
元件式軟體開發(Component-based Software Development, CBSD)被認為是提高軟體開發效率和質量的有效方式之一,且在目前各大軟體專案,以及分散式系統中得到廣泛的應用。元件式軟體的精髓簡單來說,就是透過開發各個軟體元件(software components),最後再將各個軟體元件組合起來,完成軟體開發的一種模式。這樣的概念類似物件導向的方法。
但軟體元件是物件導向概念的延伸,將物件導向的概念之上再建立一層抽象層(abstraction layer),將程式分割成較小的組合單元(building blocks),兩者皆強調軟體再用性(reusability),並強調物件或元件間的介面溝通能力。至於兩者的差別,軟體元件強調由其介面(Interface)及實作(Implementation)所組合而成,元件的實作則任由軟體開發者決定,通常由一些物件完成。元件內部實作通常不為外界所能看到,即是具有如物件導向概念中的封裝(encapsulation),且實作的修改通常並不影響最後的應用程式,而元件間的溝通管道與其介面則是在執行該軟體元件的平台建立之時就已經定義,並不需要元件開發者重新設計元件間如何交換資訊。
軟體元件是軟體重用(software reuse)的基本單元,透過完整且固定的一組介面定義對外連接(connecting, or binding),使的元件式軟體開發更容易達到重用效果。以元件實作方面來說,一個軟體物件必須要遵守其對外連接的介面,才能成為一個元件。而運行元件的平台則稱為應用程式伺服器(application server),或中介軟體(middleware),提供元件運行的環境、元件間資料傳輸與共用、提供系統服務等。SLIM即是所謂的中介軟體,或稱為Runtime layer,支援多個元件同時執行,並組合成應用程式。
軟體元件的開發則包含整體結構(Architecture)、領域塑模(Domain Modeling)、元件規格(Component Specification)等。整體結構主要探討軟體架構(Software Architecture)的問題;領域塑模則藉著對特定問題或應用領域的元件模組建立達到較高度的軟體重用;元件規格則討論如何運用語言文字或圖形方式對元件內部加以描述,使其符合元件間溝通的傳輸介面,以及為該元件之中介軟體所利用。
整體結構與領域塑模的建立與運用以採用物件導向方法為佳,元件規格也是以UML (Unified Modeling Language)或XML(Extensible Markup Language)建立為佳。元件式軟體開發可以定義為使用物件導向分析與設計,物件導向程式設計,採用適當的元件介面規格,配合設計樣式(Design Patterns)及應用框架(Application Framework)的運用,將可執行程式零件包裝成軟體元件,或採用現成的軟體元件,佈署在應用伺服器平台上,以便執行與調校的一連串方法,藉由適度的重用性將軟體開發生產效益最大化。
元件式軟體開發的優點包含提升軟體重用性、提高軟體維護性等。因此目前軟體界中已經有多個成功採用元件式軟體開發的軟體工具,如Microsoft的COM(Component Object Model)技術、OMG(Object Management Group)提出的CORBA(Common Object Request Broker Architecture)、用於Mozilla軟體平台的XPCOM(Cross Platform Component Object Model)、Sun提出的EJB(Enterprise Java Beans)、OpenOffice.org中的UNO(Universal Network Object)等等。所有這些平台中的元件式概念皆應用於多個程式語言互相溝通,或是透過網路來達成遠端互相通訊的目的,抑或把軟體分割為多個元件,並利用這些元件組成一個完整的應用程式。
以嵌入式系統軟體開發而言,除了執行Windows系統的WinCE、Windows Mobile嵌入式平台,具有.NET整合開發環境,因此不討論之外,SLIM的目標在於漸漸加入嵌入式系統市場的嵌入式Linux系統之上。由於嵌入式Linux系統上並無現成且實用的元件式軟體開發環境,隨著嵌入式系統應用越來越多元,從手機到PDA的整合,以及多媒體隨身裝置的普及化,嵌入式系統軟體開發愈顯重要。因此軟體開發比以前更甚於重視軟體重用的概念,以縮短軟體開發與整合時間,同時嵌入式系統也更重視其執行效能與軟體強健性(robust-ness)。因此以元件式軟體開發的優點與其特性,我們希望嵌入式軟體開發也可以使用元件式的開發流程,加速開發時間,同時並不犧牲軟體的執行效果,作最少的開發限制,且對於開發者而言易於學習。
因此我們建立一個以元件導向式軟體開發為基礎的中介軟體平台,SLIM即為支援此元件式軟體開發的中介軟體,支援多個元件同時於其上執行,並互相作連結以建立應用軟體;軟體開發者將從元件式軟體開發流程中能更快速的開發軟體,並利用元件間的組合與資料傳輸管道建立不同的應用程式,而最上層使用者(end user)則幾乎對於該中介軟體沒有任何實質上的感覺。
Figure
4: SLIM核心整體架構
SLIM的整體的系統架構大致如Figure 4所示,SLIM主要由Embedded Middleware部份為其核心,其中包含一個整合的中介軟體API集合,讓上層的SLIM元件使用SLIM核心的功能與資源。上層的應用程式由多個元件組合而成,而元件間透過資料傳輸介面作溝通,並具有圖形使用者介面的設計。在圖4右上部份則是SLIM核心對外的控制介面,可經由此介面與未來即將完成的Eclipse Platform整合,Eclipse的SLIM plugin將可以透過GUI的工具組,直接執行如islim的功能,提供圖形化、更容易的使用方式。
SLIM核心起始時運作基本上具有以下流程,在設計元件時請謹記核心的行為:
循序呼叫(依照元件ID)各元件的initialize()。
當1完整結束後,循序(依照元件ID)將各元件的process()以執行緒的方式執行之。
當所有元件的process()執行緒皆正常產生後,核心提供各元件間的管理、資料傳輸,並提供runtime環境,供各元件使用資源與功能。
新的元件與應用程式需開始執行時,同樣依照1,2的步驟,SLIM核心將可以在其他應用程式還在執行時再開始執行新的應用程式(但目前islim只支援單一應用程式的測試與執行)。
當某元件的process()結束後,該process()的執行緒也將結束,因此核心將會知道某元件已經結束執行,並呼叫其finalize()。
當所有元件都正常執行finalize()後,SLIM核心即結束。
因此請記住每個元件的執行模式都是以多執行緒的方式,但每個元件間並不需要透過同步化的機制來交換資料,關於交換資料的部份,根據CSBD概念,只能夠過統一、固定的管道去實行,這就是SLIM的資料傳輸通道。SLIM的資料傳輸通道可以以1對1或1對多的模式連接元件的輸出與輸入埠,並在內部已實作同步化機制與資料緩衝,使用者只需要固定呼叫SLIM提供的資料傳輸API,即可以在元件間同步傳輸資料。關於事件接收,使用者也只需要實作事件接收函式,即可具有元件專屬的event handler。
以圖4來說,SLIM還具有元件看門狗(component watchdog)的實作,專門為了監測不正常執行的元件,在其不正常執行時予以適當處理。此部份的功能於4.2節詳述。
SLIM在未來的版本並將整合三個部份,分別是Memory Monitoring、Resource Manager, 以及GUI Engine。敘述如下:
Memory Monitoring:於本實驗室另外的計劃SCREAM Library中,具有對於記憶體池(memory pool)與自動指標(auto pointer)的實作,其中加入自動偵測記憶體錯誤的能力,以及具有各式記憶體相關API,提供各元件開發者使用,達到記憶體保護與監測的功能。
Resource Manager:於SCREAM Library中,具有SCREAM Thread等部份,具有管理執行緒的部份,提供元件開發者適時使用。
GUI Engine:目前尚未實作,主要在於提供元件開發者方便利用XML定義元件自己具有的GUI類型,該GUI將被SLIM核心的GUI引擎自動產生,並可以透過SLIM核心與該元件內部實作連結,達到可互動式的元件GUI。
基本上,SLIM可以看成是CBSD的中介軟體或元件伺服器,整合作業系統與其他函式庫,如GUI、執行緒、記憶體等功能,提供統一介面給元件利用。Figure 5顯示SLIM的概念,介於傳統應用程式與作業系統間,提供如GUI、多媒體與傳輸功能,以C++ API或SLIM元件的方式供上層應用程式開發者使用,並具有SLIM開發環境(目前只包含islim工具,未來將有Eclipse整合開發環境),提供多個程式語言連結(目前Windows版SMP已可以使用Java為開發元件的程式語言,SLIM部份也尚未開發完畢。),以及連結元件的應用程式組合工具(Composer,目前為islim的功能之一,未來也會整合至Eclipse介面,請參考3.2節)等。
Figure
5: SLIM Middleware
SLIM上的軟體開發流程,參考軟體工程的統一開發流程,分別敘述如下。請注意,本節主要說明在SLIM上可行的軟體元件開發流程,並提到尚未完成的SLIM Eclipse plugin,目前皆需手動編輯XML,或利用如Vim等編輯工具。
計劃階段(Planning):建立元件的使用者需求,並察看分析現有的元件庫中是否有可重複利用的元件。
設計階段(Designing):利用Eclipse的元件設計工具(目前尚未完成,需自行編寫元件XML),設計該元件的對外介面、統一的屬性等,並決定元件內部的程式架構,撰寫需求規格等。
編寫程式、實作階段(Coding):利用Eclipse整合開發環境編寫SLIM元件程式碼(目前尚未完成,請利用各式程式碼編輯器編寫元件程式)。
編譯、測試階段(Compiling and Testing):利用Eclipse編譯元件(目前尚未完成,參考4.3節建立Makefile的方法),將編寫好的SLIM元件編譯成shared library。並利用Eclipse的Composer Tool(目前尚未完成,請利用islim介面連結,參考3.1節,或是參考2.5節自行撰寫SLIM應用程式專案XML檔),組合各式已開發好的元件,執行並做測試(目前尚未完成,請利用islim執行各元件組合而成的應用程式)。
完成開發(Releasing):利用Eclipse的Release Tool(目前尚未完成,請利用SLIM codegen tool,參考4.5節),將設計好的SLIM應用程式(元件的組合)自動產生執行檔,製作發行目錄與壓縮檔,完成開發。
本節說明如何在SLIM上開發元件。相關章節為2.4,請參考2.4的範例,有關元件介面定義的XML格式,請自行參考2.4,本節不再多作重複的說明。
本節主要說明元件開發者可以利用的API,有關使用者可以利用的完整API,請參考doxygen所產生的SLIM API文件,相關使用方式在2.3.3。
在此列出public的API,並做簡單解釋:
Public Types
enum port_type { INPORT, OUTPORT }
提供一些有關於輸出輸入埠的enum型別,分別代表輸出、輸入類型
enum port_model { DATA_PORT, SIGNAL_PORT }
提供關於一個埠的接收類型,分別為同步資料埠(DATA_PORT)與非同步事件埠(SIGNAL_PORT)
Public Member Functions
元件連接埠是否連結之API組
bool inport_connected (port_model model=DATA_PORT)
查看是否全部的同步資料輸入埠(DATA_PORT)或非同步事件輸入埠(SIGNAL_PORT)皆已連接
bool
inport_connected
(int port_id, port_model model=DATA_PORT)
查看是否某特定port_id的同步資料輸入埠(DATA_PORT)或非同步事件輸入埠(SIGNAL_PORT)已連接
bool
outport_connected
(port_model model=DATA_PORT)
查看是否全部的同步資料輸出埠(DATA_PORT)或非同步事件輸出埠(SIGNAL_PORT)皆已連接
bool outport_connected (int port_id, port_model model=DATA_PORT)
查看是否某特定port_id的同步資料輸出埠(DATA_PORT)或非同步事件輸出埠(SIGNAL_PORT)已連接
用來設定該同步連接傳輸通道(DATA_PORT)的狀態,譬如可以設定一個EOF的狀態,則後端元件利用get_buf_status即可得知目前傳輸通道處於什麼狀態,並依據傳回來的status做判斷。可以自行發揮使用,即是透過一個integer傳輸狀態。
enum { NORMAL = 0, RESET, INPUT_EOF, OUTPUT_EOF};
一個代表傳輸通道狀態的列舉類別,可自行利用或定義。
void set_buf_status (port_type port, int port_id, int status)
設定傳輸通道的狀態
int
get_buf_status
(port_type port, int port_id)
取得傳輸通道的狀態
設定或取得元件於XML定義之屬性
存取屬性,使用template function實作,使用方法為
get_property(“my_property_name”, my_local_member);
get_property將會自動自XML取得my_property_name這個名稱的屬性,並依據my_local_member的型別,將my_property_name屬性的值自動轉型,存放於my_local_member變數中。注意,my_local_member只能為單純的C++預設型別,並不可以為string型別。
template<class Type> bool get_property (const char *property_name, Type &data)
從XML定義中取得元件的某個名為property_name的屬性,並將其值儲存到類型為Type的data變數中。型別會自動轉存至data變數,支援的型別只限於如int, bool, double, float等基本類型。
string & get_property (const char *property_name)
從元件XML中讀取名為property_name的屬性,並以string類別回傳其值
此函式用於當取出的屬性型別為string時使用。使用方式如下:
string
my_value = get_property(“my_property_name”);
bool set_property (const char *property_name, string &data)
此函式則是設定元件中稱為property_name的屬性值為data,元件的屬性皆會存放在元件自己的private member內一個map中。set_property即會將新值data儲存於此map結構內。由於屬性值皆可以string類別代表,因此僅提供以string類別的data為參數的函式
此組函式可以用來依照自己的需求,設定核心內部的Signal watchdog對於本元件的容忍時間。超過timeout值,SLIM核心即會認定元件的event handler不正常執行。
void set_signal_timeout (int usec)
設定元件的事件處理函式,當SLIM判斷其不正常執行時的timeout限制,單位為usec。
int get_signal_timeout (void)
取得元件的事件處理函式,當SLIM判斷其不正常執行時的timeout限制值。單位為usec。
建立Signal封包
SMPSignal
*create_signal
(SMP_SIGNAL_TYPE
type=SMP_USEREVENT)
一個建立SLIM中代表事件的物件:SMPSignal。SMP_SIGNAL_TYPE為指定的事件類別列舉。目前SLIM只支援SMP_USEREVENT這種類型的signal。請參考4.2.2節有關事件處理函式的使用方式。
有關SMP_USEREVENT的詳細定義為:
/*! the custom signal */
struct SMPUserEvent{
/*! signal type */
SMP_SIGNAL_TYPE type; //SMP_USEREVENT
/*! user defined data in integer format */
int code;
/*! user defined data type */
void *data;
};
使用範例:
SMPSignal *sig = create_signal();
sig->user.code = 100; //user-defined signal code
sig->user.data = (void*)mydata; //user data
smp_signal(0,
sig); //send this signal to port 0
設定、尋找等雜項函式
bool exit_check (void)
檢查目前核心是否要求該元件中止執行。若是,此函式將回傳true,元件將有義務馬上跳出process()內的主要回圈,並結束process()執行。
exit_check()於SLIM的元件中具有很重要的特性。若SLIM看門狗模組有啟動,那麼exit_check()就是判斷元件是否timeout的重要關鍵。若SLIM必須強制停止元件的執行時,依據thread的設計樣版中的方式,元件必須自己結束thread function的執行,也就是process()的執行,才不會發生問題,因此元件內部必須常常檢查exit_check(),才能使該元件正常結束。
void slim_exit(void)
要求SLIM結束執行的函式。常用於GUI元件中,使用者關閉視窗所必須發出的結束要求。
bool is_realtime (void)
檢查核心是否以real-time scheduling的方式執行本元件,若是,則回傳true。
int get_id ()
找出本元件在SLIM內部的唯一ID值是多少,回傳int型別id值。
void set_watchdog (bool enabled)
設定SLIM的元件看門狗是否執行
void set_signal_watchdog (bool enabled)
設定SLIM的signal看門狗是否執行
void unregister_watchdog ()
自SLIM的元件看門狗反註冊本元件,即是要求watchdog都不要監測呼叫此函式的元件的執行狀況。用於該元件可能具有自己的Event loop,如GUI類型的元件。請參考7.0的元件設計部份問題。
Virtual Member Function: 使用者必須實作的部份
關於此部份,請參考2.4.1的說明。
virtual int initialize ()
元件初始化時的區塊,等於是元件自己的constructor。
virtual int finalize ()
元件結束時的區塊,等於是元件自己的destructor。
virtual int pause ()
元件暫停時需額外執行的程式碼。目前尚未支援。
virtual int resume ()
元件由暫停狀態重新繼續執行時,需額外執行的程式碼。目前尚未支援。
virtual int process ()=0
元件的主要程式碼區塊。該函式會被一個獨立的執行緒去執行,因此若需要有main
loop,元件開發者必須自己實作。process()中通常會放入與其他元件溝通的API,此函式最常見的實作情形是,由元件的input
ports讀入資料,處理,接著把處理後的資料經由output
ports送出。
virtual int property_handler ()
從元件的XML定義中的元件屬性擷取資料到C++ member的程式碼,可以放置於此。如get_property()這個API。該函式會比initialize()還先執行,且若使用者經由islim的介面更改某元件的屬性,SLIM核心也會自動呼叫此函式,把新的值讀入C++程式內部。
注意,property_handler()在SLIM核心中的執行,會早於任何其他函式。因此initialize()內部可以使用在property_handler()內已經初始化過的變數。
本小節說明有關SLIM元件間傳輸資料使用到的部份,獨自在此小節作說明
元件間同步傳輸資料
(以byte為單位,
byte-oriented)
延遲(blocking)式I/O,即是若資料還沒抵達(或還不能寫入),會等待至需求的大小才回傳
ssize_t
smp_read
(int port_id, void *buff, size_t nbytes)
如同C標準函式庫中的read,指定由port_id這個input port讀取nbytes大小的資料至buff指標。
ssize_t smp_write (int port_id, const void *buff, size_t nbytes)
如同C標準函式庫中的write,指定由port_id這個output port送出nbytes大小的資料,資料存放於buff指標。
非延遲(nonblocking)I/O,即是不管有無成功,都會馬上回傳值
ssize_t smp_read_nonblock (int port_id, void *buff, size_t nbytes)
同smp_read,但只限於單獨一次的讀取,也就是只限於目前buffer上有的量,超過這個量就只會傳回這麼多的資料,並不會等待新資料抵達buffer內部。
ssize_t smp_write_nonblock (int port_id, const void *buff, size_t nbytes)
同smp_write,但運作方式同於smp_write,只會寫入目前buffer上剩餘的空間,超過的資料只會被忽略,並不會等待buffer內部資料被消耗。
元件間同步傳輸資料 (以packet為單位, message-oriented)
Message-oriented的API Set同樣分延遲與非延遲I/O版本
ssize_t
smp_p_read
(int port_id, packet
*p_buff, size_t npackets)
同於smp_read,但以packet為單位傳輸。目前尚未支援。
ssize_t smp_p_write (int port_id, const packet *p_buff, size_t npackets)
同於smp_write,但以packet為單位傳輸。目前尚未支援。
ssize_t
smp_p_read_nonblock
(int port_id, packet
*p_buff, size_t npackets)
同於smp_read_nonblock,但以packet為單位傳輸。目前尚未支援。
ssize_t smp_p_write_nonblock (int port_id, const packet *p_buff, size_t npackets)
同於smp_write_nonblock,但以packet為單位傳輸。目前尚未支援。
實作Event Handling Function
若一個元件具有至少一個的事件型態輸入埠(非同步資料傳輸),則下面這個成員函式必須被繼承,以提供元件自己的Event Hanlding的函式:
virtual int SMPFilter::signal_handler(SMPSignal *sig);
SMPSignal的定義如下:
class SMPSignal{
public:
SMP_SIGNAL_TYPE type;
uint8_t dest_port;
uint8_t ref_count;
union{
SMPKeyboardEvent key;
SMPMouseMotionEvent motion;
SMPMouseButtonEvent button;
SMPUserEvent user;
};
};
SMPSignal目前於SLIM中只支援SMPUserEvent這個型別,而ref_count這個值為SLIM內部控制,作用在於若該訊號封包已經完全被處理完畢後,ref_count會變成0,因此SLIM核心會自動將該封包刪除。dest_port同樣為SLIM內部自動設定,使用者不需要修改。
SMPSignal的使用方式請參考第70頁的[建立Signal封包]中的範例。
元件的編譯,透過Makefile來完成。請先確定你的元件資料夾是放置於SLIM根目錄下的components資料夾內。
一個基本的SLIM元件其Makefile架構如下:
1 CC = g++ -g
2 CFLAGS = -DUSE_PTHREAD -DX86_LINUX -I../../
3 CFLAGS_LIB = -fPIC
4 CFLAGS_SHARED = -shared -Wl,-soname,
5 LFLAGS =
6 FILTER = component_name
7 VERSION = ` (echo "cd SMPFilter"; echo "cd Filter"; echo "dir") | xmllint --shell *.xml | tail -n 2 | grep content= | cut -d = -f2`
8 TARGET = $(FILTER).so.$(VERSION)
9
10 all: filter.so
11 @ ln -sf $(FILTER).xml $(FILTER)-$(VERSION).xml
12 $(FILTER).o: $(FILTER).cpp
13 $(CC) $(CFLAGS) $(CFLAGS_LIB) -c $(FILTER).cpp -pthread
14 filter.so: $(FILTER).o
15 $(CC) $(CFLAGS) $(CFLAGS_SHARED)libfilter_$(TARGET) -o libfilter_$(TARGET) $(FILTER).o ../../libsmpkernel.so.1.0 $(LFLAGS)
16
17 clean:
18 @ rm -f *.so* *.o *-$(VERSION).xml
其中使用者必須修改的部份為第4行,請把component_name換成你的元件的名字。該名字同時為cpp的檔名、C++的類別名稱,與xml檔的檔名。你的元件的資料夾名稱同時也必須是以filter_開頭,接著你的元件名稱的命名法,因此SLIM才能自動化的把你的元件加入Makefile中自動編譯並複製相關檔案到系統的元件庫內。
▲ 請注意第4行的最後不能有任何空白字元。
若一個元件需要使用其他的函式庫,則使用-l參數加在第5行的後面,利用mp3decoder所使用的libmad,第5行就變成:
LFLAGS = -lmad
若使用多個檔案,必須增加Makefile的規則時,請自行參考Makefile的格式,自行加入此Makefile。於元件內的Makefile將會被上層(components目錄)的Makefile所呼叫,而components的Makefile則會被SLIM根目錄的主要Makefile所呼叫。
關於SLIM元件的測試與除錯,目前並沒有提供相關的工具使用。因此可以利用GNU Debugger(gdb)來對islim執行檔作多執行緒除錯。相關使用方式如下,詳細的gdb使用方式請參考gdb的網站:http://sourceware.org/gdb/
以下為利用pcmplayer與freader連接而成的Project XML,使用gdb對islim作debugging pcmplayer元件的方式。請先找到kernel.cpp對於SMPKernel::run函式定義的位置,接著才執行run指令。如下範例所示:
$> gdb ./islim
(gdb) break SMP::SMPKernel::run
(gdb) run -r repository/ -p project/pcm_player.xml
...
SMP#> start
...
Breakpoint 1, SMP::SMPKernel::run (arg=0x8090a48) at kernel.cpp:717
717 SMPFilter *f = (SMPFilter*)arg;
(gdb) break pcmplayer.cpp::117
Breakpoint 2 at 0xb7eda827: file pcmplayer.cpp, line 117.
(gdb) cont
Continuing.
==>freader v2 processed...
[New Thread -1231344752 (LWP 23385)]
[SMP]: waiting for threads to join...
[Switching to Thread -1231344752 (LWP 23385)]
Breakpoint 1, SMP::SMPKernel::run (arg=0x8090378) at kernel.cpp:717
717 SMPFilter *f = (SMPFilter*)arg;
(gdb) cont
Continuing.
==>pcmplayer processed...
Breakpoint 2, pcmplayer::process (this=0x8090378) at pcmplayer.cpp:117
117 if (rc == 0) {
目前GDB的frame就是在pcmplayer元件的process()的thread了,接著可以對gdb下達任何相關指令,如印出變數值等:
(gdb) print rc
$1 = 3760
(gdb) where
#0 pcmplayer::process (this=0x8090378) at pcmplayer.cpp:117
#1 0x0804beca in SMP::SMPFilter::process_wrapper (this=0x8090378) at filter.cpp:458
#2 0x08052395 in SMP::SMPKernel::run (arg=0x8090378) at kernel.cpp:740
#3 0xb7c8631b in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
#4 0xb7c0f57e in clone () from /lib/tls/i686/cmov/libc.so.6
(gdb)
以上大致簡介如何利用GDB作SLIM元件的Debugging。除了gdb,也可以使用cgdb,一套利用curses函式庫建立的更方便使用的gdb,以及如ddd等具有圖形介面的gdb。關於更多gdb相關文件,請參考相關網站或書籍。
SLIM的Application Code Generation Tool,簡稱codegen tool,以Perl script開發,提供直接將SLIM Application XML轉成C++原始碼的功能。自動產生的C++原始碼主要使用到SLIM核心直接提供的較低階的函式,直接透過SLIM runtime執行,產生的程式碼約100行上下(以3個元件為一個應用程式測試),該程式碼於執行期間動態連結SLIM核心函式庫,即libsmpkernel.so,形成一個獨立運作的應用程式執行檔,不透過islim即可運作。
由於SLIM codegen tool還在開發中,因此具有的功能有限。codegen tool尚未支援多個同名元件存在於同一個SLIM Project XML檔案,也尚未支援多個<Group>標籤存在於同一個SLIM Project XML檔案中。使用上請特別注意。也請密切注意更新版的SLIM。
有關SLIM codegen tool的使用,非常簡單,其執行格式為下:
$codegen> ./gen.pl
Please specify the XML to read!
./gen.pl <path_to_XML_file>
執行時會詢問使用者兩個問題,分別是輸出.cpp的檔名(可不加上cpp字樣),以及設定SLIM元件庫的搜尋路徑。預設是''../repository'',也是SLIM核心Makefile的預設路徑,因此直接按<Enter>使用預設值即可,除非您的元件庫.so與.xml檔案放置於其他的目錄。若SLIM codegen tool出現Successfully created source code,代表原始碼產生成功。
接著可以透過make與make app指令,產生一個standalone的binary release目錄,請參閱2.7中的範例使用。
File Reader/Writer為一簡單的檔案讀取、寫入元件,其他元件可以夠過這個元件加入循序存取檔案的需求,譬如播放影片與音樂等。
File Reader相對來說較File Writer複雜許多。File Reader具有讀取檔案或讀取整個目錄的功能,並具有重複讀取與否的設定值,同時會透過其SIGNAL_PORT的連接埠發送目前正在讀取的檔案名稱與進度。因此File Reader具有5個屬性,第1個為buffer_size,代表一次從檔案讀取最多多少個bytes的資料,存進元件內部的緩衝區,預設為65536 bytes,第2個為filename,若filename為空字串,會於該元件initialize時詢問使用者,filename可為一個目錄的path或一個檔案的path,路徑可為相對路徑(islim執行檔位於的目錄的相對)或絕對路徑,而決定是目錄或檔案的設定,則靠第3個參數read_dir。若read_dir為1,則代表目前把file reader當成是directory reader。最後一個參數則為repeat,設為1則代表重複讀取目前正在讀取的檔案。
File Reader具有一個DATA_PORT的輸出連接埠,把資料內容傳輸給其他元件;具有一個SIGNAL_PORT的輸入連接埠,用來接收控制訊息的事件,譬如換下一個檔案、開啟重複,或暫停讀取等功能;File Reader還具有兩個對外的SIGNAL_PORT的連接埠,分別以事件的方式輸出目前正在讀取的檔案名稱與讀取進度。
File Writer則相似於File Reader的使用方式,但只具有把資料寫入檔案的功能,並沒有事件輸出入埠。
Timer是一個具有一個非同步事件輸出埠的元件,提供固定間隔的事件觸發。
Timer具有Interval這個屬性,使用者可以設定發出事件的間隔時間,單位為us。Timer夠過usleep函式將自己睡眠,然後透過此非同步signal port,發送一個SMPSignal*型別的事件,其中於SMPSignal::user中的data欄位,填入目前發送的訊息次數的累計值,第一次發送的序號為1。SMPSignal::user的型別是SMPUserEvent,請查閱slim目錄下的signals.h。
Timer的第二個屬性為Repeat Count值,告知Timer該發出多少次的事件。若輸入0,則代表無限。
配合Timer的使用,可以固定觸發某些事情的發生。
Audio/Video Player分別都具有一個同步資料輸入埠,分別接收音樂與影像的Raw資料,然後透過音效卡或顯示卡播放音樂與影片。
Audio Player的名稱為pcmplayer,代表是輸入PCM(Pulse-code Modulation)格式的Raw音效資料,具有3個屬性,分別是channel,代表輸出聲道數,預設為2,代表雙聲道;period_size,代表多少個frame為一個period,預設為32個frames;sampling_rate則代表播放的聲音取樣頻率多少Hz,預設為44100。透過3個屬性的設定,可以對進來的聲音作適當的播放。
Video Player的名稱為yuvplayer,代表是輸入YUV格式的Raw影片資料,格式為YUV 4:2:0。yuvplayer元件並無屬性,但會於initialize時,詢問使用者影片資料的大小(如:352x288)。Figure 6是使用yuvplayer的視窗擷取圖。
Figure
6: YUV Player執行視窗擷取圖
目前只支援解碼器(Decoder),且唯一支援的Audio/Video解碼器為MP3的解碼器。Video部份目前還有多個Windows版本中的SMP元件,等待移植至SLIM上。
MP3解碼器使用Linux上的開發原始碼軟體mad,利用libmad函式庫作MP3解碼。MP3解碼器的名稱為mp3decoder,不具有屬性設定,具有一個輸入端、一個輸出端的同步資料埠,用於接收MP3格式檔案資料,預設輸出44100Hz雙聲道的PCM格式音效Raw資料。
未來MP3解碼器也會改版,使用本實驗室自行開發的MP3 Decoder。
未來預計即將具有的音效codec有AAC Encoder/Decoder, MP3 Encoder,而視訊部份的codec則有MP4 Encoder/Decoder, H.264 Decoder等。
Play Control是一個控制播放器的元件,可以控制音樂或影片的播放,若其他元件支援,還可以讀入現在播放的檔案名稱、播放進度的資訊。Play Control同時具有基本的多媒體播放控制,如開始播放、暫停、上下首歌,以及重複播放的功能。
Play Control元件利用定義於signals.h的enum SLIM_DEFAULT_SIGNAL_ID中的各個預設Signal事件碼來定義每個GUI事件的會發射出的event,並利用SIGNAL_PORT類型的傳輸通道控制其他元件。
Play Control的連接埠全為SIGNAL_PORT類型,具有兩個輸入、一個輸出的事件連接埠,分別是取得現在播放曲目的檔名資訊、播放進度資訊,以及送出控制事件的功能。
目前支援playcontrol所定義的部份事件碼的元件為freader與PCM Player元件。Figure 7為其GTK介面的螢幕擷取圖。
Figure
7: playcontrol元件的GTK介面,正在播放一首名為cherry
lover的mp3音樂檔
另外SLIM於5月底時提供一個嶄新的功能,可以經由使用者撰寫圖形使用者介面的描述語言,讓SLIM核心自動產生真實的GUI,並可以與該元件互動。詳細使用方式尚未具有文件說明,請參考SLIM發行目錄下的component-MG目錄中的MG_playcontrol_auto這個元件,裡面具有大致的功能使用範例。
SLIM內部整合MiniGUI這個嵌入式系統專用的圖形使用者介面系統,SLIM將讀取XML描述式,自動轉換為可與使用者互動的GUI畫面。
這裡簡單展示一下大致的概念,以步驟的方式展現:
以XML撰寫GUI描述式:
如Figure 7這樣的GUI,可由以下XML描述之:
<frame caption="SLIM Play Control" width="320" height="200" xposition="0" yposition="0">
<label name="LABEL_DISPLAY" caption="Play File:" width="100" height="30" xposition="20" yposition="10" />
<edit name="edit_filename" text="none" width="180" height="30" xposition="120" yposition="10" />
<slider name="slider_bar" orientation="horizontal" min="0" max="100" value="0" minortick="1" majortick="10" width="280" height="30" xposition="20" yposition="40" />
<button name="BUTTON_PLAY" caption="Play" width="40" height="30" xposition="20" yposition="100"/>
<button name="BUTTON_PAUSE" caption="Paus" width="40" height="30" xposition="80" yposition="100"/>
<button name="BUTTON_STOP" caption="Stop" width="40" height="30" xposition="140" yposition="100"/>
<button name="BUTTON_PREV" caption="Prev" width="40" height="30" xposition="200" yposition="100"/>
<button name="BUTTON_NEXT" caption="Next" width="40" height="30" xposition="260" yposition="100"/>
<checkbutton name="BUTTON_REPEAT" caption="Repeat" value="0" width="100" height="20" xposition="20" yposition="140"/>
<checkbutton name="BUTTON_REPEATALL" caption="Repeat All" value="0" width="100" height="20" xposition="200" yposition="140"/>
</frame>
於該元件內部撰寫GUI處理函式:
virtual void GUI_event_handler(void *arg);
裡面主要著重於哪個widget發出的訊息該做何種處理
於元件內部撰寫GUI初始化與結束函式:
virtual void GUI_initialize();
主要是初始化各個UI widget,給定初始值等等。
virtual void GUI_finalize();
主要用於GUI結束時伴隨而來的處理程式
將SLIM編譯為支援MiniGUI引擎,即可完成
於SLIM根目錄下達make MINIGUI_ENGINE=1即可
另外make也支援CROSS_COMPILE這個參數,例如編譯為arm的系統時,只需下達make CROSS_COMPILE=arm-linux- MINIGUI_ENGINE=1
JACK全名為Jack Audio Connection Kit,是一個音效伺服器軟體,提供其他軟體一個共同的資料傳輸介面,該介面可以將各個支援JACK協定的軟體以非常低的延遲時間互相做同步溝通,交換音效。JACK將各個軟體的運作間,達到sample sync的要求,並提供統一的傳輸控制(jack transport)。JACK的系統架構請參考Figure 8,並參考JACK網站(http://jackaudio.org/)。
Figure
8: Jack系統架構圖
JACK上的各個client(各都是獨立的process),都是callback based的執行方式,且在固定間隔(interval)內會被重複呼叫到。於JACK上的client必須確保於固定時間內執行特定的音效計算需求,才不會被JACK丟掉(drop out)。因此各個client與jack都必須是以realtime的形式執行。Figure 8為JACK的結構圖,原始來源為http://jackaudio.org/,作為參考。
以某方面來說,JACK類似於SLIM,但不同之處在於:
JACK在執行每個client的callback函式時都遵循固定順序,每個JACK client的callback並不是以執行緒的方式去執行。
JACK執行每個client時都具有特定時間間隔,如sample rate為48000Hz,buffer size為512個frames,則每次client被呼叫的頻率為93.75次每秒。SLIM則沒有此一特性,SLIM呼叫每個client(即SLIM元件)的process()時,同時產生該元件自己的執行緒,個別獨立執行,並透過傳輸管道互相傳輸資料。
Figure
9: Jackport與FreqTweak於JACK上運作
SLIM具有兩個JACK相關的元件,分別作為輸出資料到JACK server,以及從JACK server讀取資料回SLIM內部的元件。透過此兩個SLIM元件,SLIM上的其他所有元件將可以很方便的連結至JACK上,等於同時享用任何可以連結至JACK的音效處理軟體。
一個應用的範例為,利用SLIM freader元件讀取mp3檔案,透過SLIM mp3decoder元件解碼,然後透過jackport輸出聲音訊號給JACK端,JACK上則執行有freqtweak程式,用來看聲音的frequency domain,接著透過JACK的ALSA端輸出到音效卡播放出來。。
Figure 9為執行以上動作的螢幕擷取。左下角為islim介面,左上方則為qjackctl這套GUI控制jackd程式的軟體,透過Start按鍵,開啟JACK Server(jackd)。左方中間的視窗為qjackctl的Connection視窗,可以見到Connection視窗中具有3個元素,放大如圖10所示:
Figure
10: SLIM jackport元件於Jack
Connection視窗內的連接圖
其中Figure 10左方為提供Output Port的Client(傳輸資料到JACK Server),右方為提供Input Port的Client(接收Jack Server的資料)。可以看到共有3個Client提供Output Port,分別為alsa_pcm(實體音效卡輸入端,透過ALSA,即為錄音)、freqtweak(處理frequency domain上的音效軟體)、以及SCREAM SMP JACKport,即為SLIM的jackport元件。提供Input Port的則具有alsa_pcm(代表接收聲音,作播放動作),以及同樣具有input端的freqtweak軟體。中間的連線則代表這些軟體間的音效資料傳輸,圖10連線代表:從SLIM的jackport把資料傳給freqtweak作處理,然後由freqtweak的output端丟給音效卡播放。並注意,所有連線都是左右兩聲道,因此兩個client中皆有兩個連線。
Figure
11: SLIM jackinput元件於 Jack
Connection視窗中的連接圖
因此在Figure 9螢幕擷取圖中,右半部的freqtweak接收SLIM過去的資料後,即時顯示frequency domain的資料,並在下方可以做處理,再即時傳送至電腦音效卡播放。
另外一個範例則為透過jackinput元件,將聲音透過cmdwrapper元件呼叫bladeenc這套MP3 Encoder,即時錄聲音成某個mp3檔案。Jack端將透過Hydrogen這套鼓聲音效處理與創作軟體,連接剛剛提過的freqtweak,透過freqtweak將聲音傳輸至音效卡與SLIM jackinput元件兩者。qjackctl的連接圖如Figure 11,全螢幕擷取圖如Figure 12所示。
Figure 12右下角為SLIM的islim介面,SLIM正在接收經由hydrogen產生且透過freqtweak修改過的鼓聲,並經由cmdwrapper元件,呼叫執行檔bladeenc將聲音檔即時壓縮成mp3檔案。因此我們可以在其他應用程式中設計我們獨創的音樂,並透過JACK與SLIM將此聲音處理過後,壓縮成MP3檔發行。
以上為使用Jack binding的兩個SLIM元件的示範。更多應用與範例將可以透過JACK與SLIM完美的結合而產生更多可能。
Figure
12: 透過jackinput,將hydrogen產生的音樂傳輸至SLIM中即時使用MP3編碼儲存
SLIM整體系統
何時會有新版SLIM?去哪裡找到有關SLIM的訊息與更新?
由於目前SLIM屬於NCKU SCREAM Lab獨立開發之軟體,且位於開發中版本,並未正式釋出,所以目前SLIM並未具有專門的網頁做介紹。但可以至以下位置詢問或找到相關更新、發行訊息:
SCREAM Lab網頁: http://scream.csie.ncku.edu.tw
SCREAM Lab網誌: http://scream.csie.ncku.edu.tw/blog/
SCREAM BBS討論版:telnet://140.116.246.180 -> L-SCREAM
SLIM Wiki (目前還沒啟用):http://scream.csie.ncku.edu.tw/wikislim/
SLIM 網頁 (目前還未建立):http://scream.csie.ncku.edu.tw/slim/
另外,具有Subversion權限使用SLIM原始碼的使用者,可以透過svn抓取最新的原始碼,先轉到SLIM根目錄下,然後執行以下指令即可:
$> svn up
SLIM使用什麼授權?
SLIM目前為止為SCREAM Lab內部使用,因此還未決定使用何種方式對外公布。最新訊息請參考SCREAM資訊。
去哪裡取得本文件的最新版本?
本文件為SLIM系統的使用者說明文件,將為於SLIM根目錄下的user_manual.pdf,具有使用Subversion下載SLIM原始碼的使用者同樣可以透過svn up取得此文件最新版本。其他使用者則可以透過瀏覽SCREAM網誌最新文章,取得更新訊息。
SLIM可以於Windows上使用嗎?
SLIM (SCREAM Linux Middleware)為專門於Unix-based作業系統上運行之中介軟體,其設計包含對於嵌入式系統的特性設計,並未考慮可以跨至Windows上執行。目前SLIM有使用Unix-specific的函式用法,以及大量使用pthread,因此還不行於Windows上執行。但本實驗室正在開發的另外一個計劃: SCREAM Library,包含對於跨平台(針對Linux與Windows兩大作業系統)有支援的執行緒,因此未來版本的SLIM並將轉移使用SCREAM Library,提供跨平台的功能。但以目前的應用範圍來說,SLIM只適合於Linux (已測試於Fedora與Ubuntu發行套件上)以及Linux-based的嵌入式系統上。
Figure
13: Windows SMP執行畫面,執行一個IPTV的模擬軟體,包含多個decoder,
loader, 網路元件,以及播放音樂的元件
若需要於Windows上使用類似SLIM的開發方式,可以參考本實驗室的SMP專案,如Figure 13所示,為SLIM的前身,也是Windows版的元件式軟體開發平台。
SLIM的開發精神與願景為何?
SLIM的設計與開發起始於Windows版的SMP軟體,當時的主要目的為指導老師:蘇文鈺老師為了整合本實驗室軟體組成員開發的軟體,並利用元件導向式的軟體開發減少重複發明輪子的事情,因此可以利用此統一平台為大家工作的環境,利用撰寫元件,與其他人能快速整合軟體。
SMP中支援的軟體元件已經具有數十種,例如本實驗室開發之MP3 decoder, ACC decoder, Mpeg4 encoder/decoder, H.264 decoder, 音效效果器、視覺化編輯元件等有關多媒體的元件,以及RTP Client等網路元件。另外也有IPTV Simulation、影音同步元件。SMP的整合開發中,並包含利用SMP系統於多個大型專案上作示範軟體與實作軟體的經驗。
鑑於元件式軟體開發的長處,以及嵌入式多媒體需求日增,本實驗室邃於2006 3月份開始訪造SMP的內部軟體設計架構,重新於Linux系統下開發Linux版本的SMP,其中改良許多SMP設計時沒有考慮到的功能與設計模式,譬如watchdog的概念,以及對於不同類型傳輸模式的支援。以不同開發者重頭開始開發Linux版的SMP,同時由於其利用範圍針對嵌入式環境作設計,改名為SCREAM Linux Middleware,以其身為一個元件式軟體開發的中介軟體為名。並以一個整合環境為最終目的,包含SLIM中介軟體本身,以及一連串相關工具的支援,為SLIM整體計劃。目前SLIM具有比Windows SMP更小的記憶體需求、更好的執行效能,以及更簡單的API設計與更彈性的元件間傳輸通道,計畫於今年(2007)年中將釋出支援GUI引擎與Eclipse整合開發環境的工具,讓在SLIM上的開發更為方便,並具有容易使用的GUI建立模式,提供嵌入式與桌上型Linux環境一個更好的軟體開發平台。
開發SLIM元件,我需要怎樣的Host端開發環境與設定呢?
SLIM全程位於Ubuntu Linux發行套件上開發,並於Fedora Linux、Debian Linux上測試過。基本上所有的Linux只要安裝有可用的pthread與libxml2函式庫,皆可以正常使用SLIM。因此開發SLIM元件,您只需要一台具備有gcc、gdb等GNU toolchain的Linux電腦即可。當然也可以透過如VMWare的軟體執行的Linux來做開發,但建議安裝Native的Linux,以增加開發效率。
至於如何設定開發環境,請參考第2章的詳細解說。
如何使用JACK與所謂的JACK client應用程式?
本說明文件不包含使用JACK的部份,請自行參考JACK的網站: http://jackaudio.org。
另外,由於支援Jack介面的應用程式非常多,繁舉網頁如以下: http://jackaudio.org/applications
便列出接近百個應用程式。請自行參考各軟體的網頁。有關如何讓SLIM也支援JACK的傳輸協定,讓SLIM上的元件也可以享用上百個音效相關的軟體,請參考5.5節。
7.0 TROUBLESHOOTING
執行islim
執行islim時出現找不到libsmpkernel.so.1.0,顯示無此檔案的錯誤?
通常此問題都是由於忘記設定LD_LIBRARY_PATH,此環境變數用於告知執行檔islim預設的共享函式庫位置。請參考2.6節說明。
執行islim時,”lsa all”列出所有元件的指令,顯示沒有任何元件,但我已經把所有元件的.so與.xml檔案放置於repository目錄下了?
請先查看 ''which repos''指令的輸出,看看是否是因為忘記設定元件庫(repository)目錄所造成的。或是執行islim時以參數-r指定你所放置的元件庫目錄位置。若已經設定,請再次確認元件庫目錄內同時具有共享函式庫.so檔案與元件定義.xml檔。
islim執行某些指令時會發生Segmentation Fault。
有些指令是之前支援,而目前版本尚未支援的。請先利用islim的help指令察看,若指令前有星號,則代表在此版本內尚未支援,有可能會發生錯誤。
另外會發生Segmentation Fault的很大可能是由於使用者輸入不正確的指令格式。由於islim尚在開發測試版本,關於指令的設定與輸入是靠單純簡單的字串比對,因此有可能是因為指令解析錯誤所造成。請依照help中的指令格式使用。
SLIM Codegen Tool
Codegen無法正常運作,會出現莫名其妙的錯誤訊息?
目前codegen是使用perl程式語言撰寫,開發尚未100%完善。且前(2007.4.28)尚未支援的SLIM Project XML檔案格式中的標籤為:
a. 尚未支援多個同名元件存在於同一個SLIM Project XML檔案
b. 尚未支援多個<Group>標籤存在於同一個SLIM Project XML檔案
因此請檢查您的SLIM Project XML是否具有以上未支援的部份。通常codegen會自動忽略不支援的標籤,但以上兩者限制,可能會讓codegen當掉,請見諒。
另外請先確定於SLIM根目錄下先執行make後,才可以使用codegen工具。
元件設計
我的元件使用到其他的GUI函式庫,如SDL、OpenGL或Qt等等。由於其中皆有各自的event main loop,我該用怎樣的設計模式,讓寫在process()成員函式內的程式碼符合GUI的模式?SLIM的watchdog總是在我執行元件沒過多久即便認為我的元件有問題,因此停止執行?
於第4章我們解釋到一般元件的的設計模式,通常於process()內具有一個main loop,其形式如下:
for(; exit_check();){
//do things
}
由於自己具有GUI元件也具有各自負責GUI動作的main loop,因此此類元件將可以不必使用上述的元件設計模式,但由於exit_check()函式是告知SLIM watchdog該元件還繼續有在執行的重要依據,所以各自的GUI main loop內沒有呼叫exit_check(),即會導致SLIM watchdog誤認為該元件沒有回應。解決的方法有二:
在該元件的initialize()區塊內,呼叫:
unregister_watchdog();
則該元件將不被SLIM watchdog所監視。因此GUI類型的元件將不會因此被系統認為不正常執行。另外也可以在SLIM應用程式XML檔案前,加註以下標籤:
<Config>
<entry name=”Watchdog” value=”0”/>
</Config>
因此該專案透過islim執行或透過codgen產生的CPP原始檔和make產生的source code,同樣將不被watchdog所影響。
因此此類型的元件可以不必遵循原本的元件設計模式,但必須事先將watchdog的監看關閉。
當我的元件只有單純使用非同步資料傳輸時(signal buffer),我是否還需要實作process()呢?非同步資料傳輸可以寫在process()成員函式中嘛?
當一個元件只有使用到非同步資料傳輸,即所謂的event/signal介面時,只需要實作一個空的process()成員函式即可。如下面程式碼所示:
int myComponent::process() {}
由於每個元件皆必須繼承自SMPFilter這個base class,並實作process()才可以成為SLIM中的元件,因此若你的元件只單純使用signal傳輸,也需要實作一個空的process()。
SLIM核心會自動偵測process()是否有內容,並自動關閉有關process()的監測作用(SLIM watchdog),因此也不需要在initialize()中寫unregister_watchdog()。
另外,非同步資料傳輸只限定於
SMPFilter::signal_handler(SMPSignal *sig);
中實作並處理,因此沒法於process()中實作直接的接收非同步資料。這麼做的原因是為了讓signal_hanlder為唯一的非同步函式處理函式,可以避免元件內部的同步化問題。因此請依照signal_handler實作你自己的處理函式,並利用
switch(sig->dest_port){ };
敘述來判別來源端非同步事件埠。
為什麼某些元件在islim上打stop或quit時並不會真正結束,造成islim當在那邊?
這有可能是因為元件內部並沒有在適當時機加上exit_check()函式。該函式用來查詢SLIM核心是否要求該元件結束執行。若一個元件在某的地方等待一些事件或情況發生的時候,若沒有加上對exit_check()的回傳值判斷的話,該元件的process()執行緒就不會return,造成該元件無法真正結束,近兒造成islim當掉的問題。
由於使用旗標(flag)來讓執行緒結束的設計模式(design pattern)被廣泛認為是安全的,因此SLIM對於元件的執行緒停止的部份同樣採用旗標判斷,即是exit_check()函式。因此請檢視您的元件process()中,是否在任何會block的地方都加上對exit_check()回傳值的判斷。
我自己撰寫的元件,若需要使用到其他函式庫,我該怎麼修改Makefile?使用islim測試我寫的元件時,會出現找不到xxx.so的錯誤訊息,其中xxx為我使用的其他函式庫的shared object檔。這又該如何解決?
若一個SLIM元件使用到第三方函式庫,依照一般程式的Makefile寫法,通常需要對GCC下達-l, -L或-I的敘述。在compgen工具產生出來的元件Makefile中,請在LFLAGS中下達有關連結的參數(如-L, -l),並CFLAGS下達有關header files的參數(如-I)。請務必確認在filter.so這條Makefile規則的最後面加入需要連結的-l參數。譬如你若使用到數學函式庫與GTK圖形介面,則參數如下:
-lm `pkg-config --libs gtk+-2.0`
若使用到如網路監測封包的函式庫Pcap,則下達:
-lpcap
如以上範例設定好元件Makefile後,還必須確認您使用的第三方函式庫的shared object(so)檔案放置於系統的函式庫目錄中,如/usr/lib或/usr/local/lib,並且具有一個以.so為結尾的連結檔,指到正確版本的shared object檔。以libz這個函式庫為例,在系統函式庫目錄下,具有一個實體檔案,兩個連結檔。
lrwxrwxrwx 1 root root 9 2007-04-17 10:57 libz.so -> libz.so.1
lrwxrwxrwx 1 root root 13 2007-04-17 17:34 libz.so.1 -> libz.so.1.2.3
-rw-r--r-- 1 root root 78276 2007-03-06 03:49 libz.so.1.2.3
相關設定請參考Linux下的ldconfig指令介紹。(i.e.: man ldconfig)
以下摘錄自http://jackaudio.org
Jack (Jack Audio Connection Kit)
JACK is a low-latency audio server, written for POSIX conformant operating systems such as GNU/Linux and Apple's OS X. It can connect a number of different applications to an audio device, as well as allowing them to share audio between themselves. Its clients can run in their own processes (ie. as normal applications), or can they can run within the JACK server (ie. as a "plugin").
JACK was designed from the ground up for professional audio work, and its design focuses on two key areas: synchronous execution of all clients, and low latency operation.
也可以參考JACK FAQ
http://jackaudio.org/faq