星期日, 5月 17, 2009

Marley & Me

「一條沒有規矩的狗和一對新婚夫妻的生活,最後男主角死了,兩個配角也生了三個小孩,The End!」

星期三, 5月 13, 2009

DirectFB on Beagleboard

DirectFB 是 graphical library,支援 input event handling、window management 等,我們藉由 DirectFB 可以在 embedded system 上建立 GUI 的環境,DirectFB 透過 framebuffer 或 /dev/mem 控制底層硬體,所以在開始之前,先確定這兩條路在 kernel 裡有一條是通的,若是走 fbdev 別忘了在 rootfs 裡建立 /dev/fb0。



雖然是「DirectFB on Beagleboard」,但和 beagleboard 沒有太大關係,我只是把它當作 demo 的平台。CPU 是 TI OMAP3530 (Cortex-A8 / armv7a) 我並沒有特別針對 armv7a 作最佳化,同時在編譯 DirectFB 時也沒有將 beagleboard 支援的 3D 功能 enable (少了 SDK...),所以以下的動作是可以套用在其他 arm 的平台上。

單純想要手動去建立一個系統,從 BusyBox 開始編起,慢慢拼湊自己想要的系統,唯一的好處是整個過程會遇到很多問題,所以會學到一些東西,對系統的掌握也更多。OpenEmbedded 是個好東西,只是每次下個指令就把系統建好的感覺很不踏實 ;)



下載每個套件的 source,由於套件的相依性,因此由 zlib 開始編譯最後則是 Lite,Lite 是以 directFB 為基礎的 toolkit,編譯它的目的只是為了執行它的 samples 驗證 directFB 是可以動的(此外,Lite 也是 DFBterm 的相依套件),如果有 touchscreen 那麼 tslib 是必要的套件。

可以直接下載每個套件對應的 build-script,直接修改,例如:
make clean
STAGING=/home/sean/openmoko/embedded-gui/dist
./configure --prefix=/usr \
--host=arm-none-linux-gnueabi \
--enable-shared=yes --enable-static=yes \
CFLAGS="-I${STAGING}/usr/include" \
LDFLAGS="-L${STAGING}/usr/lib"
LIBS="-lz"

make DESTDIR=${STAGING} install
把 STAGING 改成你自己的工作目錄, --host 則是你使用的 cross-toolchain。另外, jpeg 及 directfb 先天營養不良,從官網抓下來的套件就無法順利編譯或安裝,所以下面的 patch 要先打上...

fix_errro_when_install.patch
fix_missing_libtool_error.patch
add_missing_header_file.patch

在編譯 (cross-compile) 套件時,configure 的動作要特別小心,好一點的狀況是有 error 產生,最麻煩的是 configure 時告訴你沒有問題,編譯時卻發生錯誤,事實上在 configure 程序就已經出錯了,通常是在作環境變數的檢查時 configure 搞混了,所以我會利用 screen 將整個過程紀錄下來,再稍微看一下。

以下面例子而言,在 configure 前,特別指定 LIBPNG_CONFIG 的用意是因為 configure 會找到 /usr/lib/libpng-config,但這是我 host (x86) 上的,並不是真正要的
STAGING=/home/sean/openmoko/embedded-gui/dist

LIBPNG_CONFIG=${STAGING}/usr/bin/libpng-config ./configure \
--prefix=/usr \
--host=arm-none-linux-gnueabi \
--target=arm-none-linux-gnueabi \
--enable-static=yes --enable-shared=yes \
...
編到 directFB 套件我們就可以先把所有產生的 header / lib / binary 等,放到 rootfs 上作測試,執行 dfbscreen 如果沒有意外的話會給你沒營養的錯誤訊息:
   ~~~~~~~~~~~~~~~~~~~~~~~~~~| DirectFB 1.3.1 |~~~~~~~~~~~~~~~~~~~~~~~~~~
(c) 2001-2008 The world wide DirectFB Open Source Community
(c) 2000-2004 Convergence (integrated media) GmbH
----------------------------------------------------------------

(*) DirectFB/Core: Single Application Core. (2009-05-15 09:48)
(!) DirectFB/core/system: No system found!
(!) Tools/Screen: DirectFBCreate() failed!
--> No (suitable) implementation found!
strace 試著找出問題點,是因為編譯 directFB 時把 /home/sean/openmoko/embedded-gui/dist 路徑寫進產生的 library 及執行檔裡,所以執行 dfbscreen 時,如果在該目錄裡找不到它需要的,便丟出錯誤訊息。找不到是必然的,因為編譯出的檔案最後是放在 rootfs 的 / 目錄下。

路徑寫到編譯產生的檔案裡是 linker 參數 rpath 造成的,如果我們是在系統下編譯套件並把該套件安裝在系統下,那麼寫入路徑是沒有問題的,但 cross-compile 就會有麻煩了,假設你編譯了套件 A 並將它安裝在 ${STAGING} ,假若套件 B 相依於套件 A,在編譯套件 B 時必須指定套件 A 的安裝路徑,這時候就有可能發生 rpath 的問題了,我是透過修改 configure 檔,把參數 rpath 改成 rpath-link 解決這個問題,編譯後可以檢查是否還有 rpath 的影響:
#!/bin/bash
find $1 -name "*" | xargs arm-none-linux-gnueabi-readelf -d | grep RPATH
change_rpath_to_rpath-link.patch
jpeg_rpath_to_rpath-link.patch

討論 cross-compile 的路徑問題可以參考 Avoiding libtool minefields, 詳細說明會遇到的狀況。繼續編譯 Lite 會出現錯誤,類似:
arm-none-linux-gnueabi-ranlib .libs/liblite.a
creating liblite.la
/bin/sed: can't read /usr/lib/libfusion.la: No such file or directory
libtool: link: `/usr/lib/libfusion.la' is not a valid libtool archive
make[1]: *** [liblite.la] Error 1
找不到 /usr/lib/libfusion.la,root cause 也是因為路徑的問題,函式庫之間會有相依性,我們也許只知道某個套件需要函式庫 A,但不清楚 A 是相依於哪些函式庫,libtool / .la 則是可以用來解決這樣的問題,只是在 cross-compile 時,反而造成問題。以下節錄 libdirectfb.la 檔:
...
# The name of the static archive.
old_library='libdirectfb.a'

# Libraries that this one depends upon.
dependency_libs=' -L/home/sean/openmoko/embedded-gui/dist/usr/lib \
/usr/lib/libfusion.la /usr/lib/libdirect.la -lpthread \
/home/sean/openmoko/embedded-gui/dist/usr/lib/libjpeg.la \
/usr/lib/libpng.la -lz -lm /usr/lib/libfreetype.la \
/usr/lib/libts.la -ldl
...
dependency_libs 會提供該套件相依的 library,但是路徑卻是錯的,解決的方法是把所有 *.la 的 dependency_libs 注解掉,取而代之的是在 configure 時就指定 linker or compiler 所需的參數:
#!/bin/bash
find $1 -name "*.la" | xargs sed -i 's/dependency_libs/#dependency_libs/g'
最後附上 lite_simple 在 beagleboard 上的執行畫面

星期一, 5月 11, 2009



星期日一早帶齊裝備後就到內湖山裡做野採,對象是青苔,除了長在山壁上的,生長在石頭上的青苔也是這次採集的目標,溪邊的山璧很適合青苔的潮溼、陰暗生長環境。



在山裡(或溪裡)活動,保持靈敏聽覺和嗅覺是很重要的,如果聽到奇怪的聲音或聞到奇怪的味道,慢慢地退到安全的地方。往溪水下游的方向走去,走沒幾公尺先是聞到一股惡臭,同時聽到一群拍打翅膀的嗡嗡聲,經驗法則附近有屍體,就回頭往上游方向了...

想起小時候和表弟在鄉下大水溝裡抓魚的恐怖記憶,抓的很開心的時候,旁邊浮來全身發漲發黑的死豬(還有死雞),所以我到現在還是會害怕看到水裡的麻布袋 ;)

人生就像飄在水面的麻布袋,不打開看,你永遠不知道裏面裝甚麼死人骨頭...









遇到剛羽化的蜻蜓幼蟲水蠆(ㄔㄞ')






儘量不要一個人跑到山裡,很難預測會有甚麼突如其來的事情發生,找個伴。這次的主角青苔正在育嬰室,如果有活下去就可以出來亮像了 ;)

比肥的



星期三, 5月 06, 2009

Bootable USB Image

前幾天,不務正業的幫公司處理工廠生產的問題,作為代工廠,系統影像檔是由客戶提供,所以測試程式不可能讓你包在出貨用的 Image 裡,一來是因為「髒」,再者是程式自身的需求或許需要某些套件的搭配,比較好的方式為測試程式量身打造一個系統。

要求很簡單,Boot From USB、越小越好、開機後直接執行測試程式,且可以簡單、快速的大量複製該測試系統,Moblin Image Creator 可以幫助我們簡化整個過程,把整個框架建好,我們可以專心在整合測試程式,同時安裝程式需要的套件、modules,接著手動修改設定檔,整個過程就像在拼圖一樣。即便有了 MIC,手動的地方還是不少,最後作出來的影像檔大小 300 MB,雖然還可以縮減,但以現在隨身碟的容量及 USB 2.0 的傳輸速度,其實意義不大;對於大量複製的要求,工廠只要執行 dd bs=1024 if=usb.img of=/dev/sd? 便可以做好測試用的隨身碟。

學習應該是這樣,首先你找到黑盒子幫你解決問題,接下來要去了解黑盒子,最後你試著做出一個很陽春但可以用的透明盒子。我將整個過程抽出重新寫成 Scripts,一樣可以作出符合要求的檔案 ;)

重點是,這樣的過程,你必須不斷地把做好的 Image 寫到隨身碟,關機,重新開機(Boot From USB),檢查作出來的隨身碟能不能正常開機,如果你真的不斷重複這樣的過程,我只能說連猩猩都會利用工具釣魚了... ;)



透過 QEMU,不必重新開機,就可以測試我們做好的隨身碟,利用 lsusb 得到 usb flash drive 的 vendor 及 product id 後,利用 qemu 模擬整個開機的過程

sudo qemu usb.img -no-acpi -usbdevice host:3538:0050





不務正業,我就是討厭 Notebook...

Kenting

四月的某個週末,因為姊夫參加在墾丁舉辦的國際鐵人三項比賽,就趁著這個機會和家人一起再回到墾丁,還好,今年四月的氣溫還是舒服的 ;)

我們不是參賽者,比較像是自由行的人,就這樣開著車沒有目地的到處跑。跑去海角七號的場景拍照,跑去四重溪享受只有我們一家人的溫泉,天空還飄著毛雨,跑去只有我們的沙灘,順便找所謂的港口茶,最後在慢速的開在漂亮的佳鵝公路上。





或許是被海趨使,回到台南後,就立刻拖著我家的狗跑到黃金海岸,站在海裡,迎著海浪的沖擊,對著海大笑(狗爬式很搞笑),等到太陽西下,遠方燈塔的橘燈和藍燈亮起,瞬間陷入沈寂裡。

像這樣把時間留給家人,也是不錯的生活(茶)...

星期三, 4月 22, 2009

BeagleBoard

農曆年後拿到的板子,到手後作了基本的測試就因為其他的事情而停頓...

左邊是 Type A 轉 mini B 的 USB 線,可以供電給 Beagleboard,下方白色接頭的線則是 USB OTG,有了它,板子可以變成 USB Host 的角色,這時就需要外接電源了(左二),另外,一張 4GB SD 卡是用來儲存 rootfs,最右邊則是 HDMI2DVI cable,有了它才能外接電腦螢幕。



自己花錢買的東西當然要好好珍惜(手上還有一片 JTAG Port 有問題的 QT2410),為了預防使用中板子被靜電打死,所以在購買時順便加買了壓克力外殼避免外力直接去接觸到硬體,開孔處也處理的很好,整體質感不錯,不會給人很粗糙的隨便感 ;)





板子上的 JTAG 是 14 PIN 的,但是我手上的 JTAGKey 是標準的 20 PIN,所以我先跑去光華商場買了一個接頭,順便做了一條線,看過電路圖後,我猜測只要把一些 PIN 接地後應該就可以用了,等有空的時候再試。



整個接好就像這樣,透過 USB Hub 外接鍵盤、滑鼠,功能的擴展性是很夠的,要有網路或無線網路也不會是問題。



最後,這是前幾天把 QT-Embedded 4.5 放到板子上的跑 Demo 程式的執行畫面,應該很熟悉吧,但是好像收不到鍵盤或滑鼠的 event,rootfs 是 based on Angstrom。(我已經把 Configure / Build Qt-Embedded 4.5 的 Scipt 及 Log 放上去,有興趣的人可以參考)

星期一, 4月 13, 2009

園藝樂

上星期一因為心情不爽上班,ㄟ,我是說身體不舒服,莫名地得了星期一症候群,請了一天假一大早就跑到附近的內湖花市裡閒晃,第一次逛花市,即便我已經生活在內湖三年了。

老實說,這種別人在上班,我卻在外面蹓達又有錢領的感覺比大家都放假的感覺還開心。

很快買好東西後,就開始我的園藝樂,不知道有多少人聽過倒地鈴這植物,我在台北的山區晃了幾次沒看過,中南部很常見,所以趁著回南部掃墓順便摘了幾株,準備種在窗台邊希望能移植成功。



我覺得最好玩的地方在於它的種子,成熟的種子是黑色,中間會有一個白色的小愛心,很特別,就像小孩子收集星砂送給喜歡的人,有人也會收集種子,裝在小玻璃瓶裡當作禮物 ;)



因為瓶罐蟋蟀一書,特地買了幾個玻璃瓶回來建立自己的瓶中世界,植物就從老姐送的銅錢草移植過去,至於將蟋蟀養在瓶子裡就不必了 ;)







就像在水族箱種水草一樣,會有分前景、中景及後景,根據植物的高低來種植,使用箝子可以幫助更容易的將植物植入,以之前種水草的經驗,因為水族箱比較大的關係,這個難多了,比較難控制。



一個早上的成果,我連吃不完的地瓜都拿去種了 ;)

Complex C Declarations

因為 olv 丟了一個複雜的 C 語言宣告給我:
 void (*glXGetProcAddressARB(const GLubyte *procName))( void )
勾起學生時代的回憶,所以把這篇 1991 年出現在 comp.lang.c 的文章挖出來,這裡可以下載完整的內容。

The "right-left" rule is a completely regular rule for deciphering C declarations. It can also be useful in creating them.

First, symbols. Read

* -- as "pointer to" ----------- always on the left side --- 指標, 指向...
[ ] - as "array of" -------------- always on the right side - 陣列, 其陣列元素為...
( ) - as "function returning" - always on the right side - 函式, 回傳值為...

as you encounter them in the declaration.

利用 "right-left rule" 可以幫助我們正確地解讀 C 語言的宣告,不論是多麼複雜,即便是不合法的宣告。在解讀的過程中,若是遇到了上述表格裡的 * [ ] ( ) 符號,則將它們視為其後相對應的解釋。

STEP 1
------
Find the identifier. This is your starting point. Then say to yourself, "identifier is." You've started your declaration.

步驟一、先把識別子(變數名或函式名稱)找出來,這時候你可以說:xxx 是一個 ...,例如 int *p[ ]

識別子是 p,翻成「p 是一個...」

STEP 2
------
Look at the symbols on the right of the identifier. If, say, you find "( )" there, then you know that this is the declaration for a function. So you would then have "identifier is function returning". Or if you found a "[ ]" there, you would say "identifier is array of". Continue right until you run out of symbols *OR* hit a *right* parenthesis ")". (If you hit a left parenthesis, that's the beginning of a ( ) symbol, even if there
is stuff in between the parentheses. More on that below.)

步驟二、檢查識別子右邊出現的符號,如果有的話,例如看到 [ ] 我們可以說「xxx 是一個陣列,它的陣列元素是 ...」,若是看到 ( ) 則翻成「xxx 是一個函式,回傳值是 ...」,接著繼續地往識別子的右邊尋找其他符號,直到識別子右邊已經沒有符號或是遇到了 ")",跳到步驟三。

int *p[ ],往識別子 p 右邊遇到了符號 [ ],右邊也沒有其他符號,翻成「p 是一個陣列,其陣列元素是...」

另外,如果遇到的是 [N],也就是帶有陣列大小的陣列宣告,我們可以這樣翻「 xxx 是一個大小為 N 的陣列,它的陣列元素是...」,若是遇到的是 (yyy),我們可以翻成「xxx 是一個參數為 yyy 的函式,其回傳值為...」

STEP 3
------
Look at the symbols to the left of the identifier. If it is not one of our symbols above (say, something like "int"), just say it. Otherwise, translate it into English using that table above. Keep going left until you run out of symbols *OR* hit a *left* parenthesis "(".

步驟三、檢查識別子左邊的符號,如果出現的是 * [ ] ( ) 就照表翻譯,若出現的並不屬於上述的符號,那麼看到甚麼就說甚麼,不需要額外的翻譯,例如看到 int 就直接翻成 int,繼續地往識別子的左邊尋找,直到識別子左邊已經沒有其他符號或是遇到了 "(",接著回到步驟二(若是識別子左右兩邊已經沒有其他符號)

int *p[ ],往識別子左邊先找到了 *,所以翻成「p 是一個陣列,其陣列元素是指標,指向...」,繼續往左邊看,遇到了 int,由於識別子左右兩邊都沒有符號了,所以完整的解讀是「p 是一個陣列,其陣列元素是指標,指向 int」

「p 是一個陣列,其陣列元素是指向 int 的指標」

Now repeat steps 2 and 3 until you've formed your declaration.

重複地套用步驟二、三,直到完成整個宣告的解讀。

我相信剛接觸 C 語言的人很難分辨上述的 int *p[ ] 與 int (*p)[10] 的差別,試著套用 ”right-left-rule” 解讀:

1. int (*p)[10],識別子是 p,翻成「p 是一個」

2. 往p 的右邊看到的符號是 ”)”,根據步驟二的說明,我們跳到步驟三檢查識別子 p 的左邊

3. 往 p 的左邊看到的符號是 ”*”,翻成「p 是一個指標,指向...」

4. 繼續往 p 的左邊檢查,遇到的符號是 ”(”,根據步驟三的說明,我們回到步驟二檢查識別子 p 右邊的其他符號

5. 繼續往 p 右邊我們遇到了 [10],翻成「p 是一個指標,指向大小為10的陣列,其陣列元素是...」

6. 繼續往 p 右邊檢查,已經沒有其他符號了,根據步驟二的說明,接著繼續講查識別子 p 左邊的符號

7. 接著往 p 左邊我們遇到了 int,因為不屬於 * [ ] ( ) 中的一個,所以翻成「p 是一個指標,指向大小為10的陣列,其陣列元素是 int」

8. 識別子左右兩邊已經沒有符號,結束

知道了 p 的宣告,在寫程式的時候,就可以避免 assign 錯誤型態的變數給它的錯誤
int main(void) {
int array[10];
int (*p)[10] = &array;
array[2] = 111;
(*p)[2] = 222;
printf("%d\n", array[2]);
return 0;
}

回頭看 void (*glXGetProcAddressARB(const GLubyte *procName))( void ),套用 ”right-left-rule”:

1. 先把識別子找出來, glXGetProcAddressARB 是識別子,翻成「glXGetProcAddressARB 是一個」

2. 往識別子右邊看到的符號是 (const GLubyte *procName),翻成「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為...」

3. 再往右邊看下去,我們遇到了 ”)”,根據步驟二的說明,我們跳到步驟三

4. 往識別子的左邊看到的符號是 ”*”,翻成「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為指標,指向...」

5. 繼續往左邊看,我們遇到了符號 ”(“,根據步驟三,我們跳回步驟二

6. 回到步驟二,我們繼續往識別子右邊找其他的符號,這時出現的是 “( void )”,所以翻成「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為指標,指向一個參數為 void的函式,其回傳值為...」

7. 再往右邊找,已經沒有任何符號,跳到步驟三

8. 往左邊找到了 void,直接翻,「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為指標,指向一個參數為 void的函式,其回傳值為 void」

9. 識別子左右兩邊已經沒有符號了,完成
「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為指標,指向一個參數為 void的函式,其回傳值為 void」再稍微修飾一下,改成「glXGetProcAddressARB 是一個參數為 const GLubyte *procName 的函式,其回傳值為函式指標,指向一個參數為 void的函式,其回傳值為 void」

void helloworld(void) { return; }

void (*glXGetProcAddressARB(char *procName))( void ) {
return helloworld;
}

int main(void) {
glXGetProcAddressARB("ARB");
return 0;
}

星期二, 3月 31, 2009

石來運轉

石來運轉取其諧音「時來運轉」,因為風水的緣故這類的裝飾品還蠻常見的,今天的故事就發生在我家裡的它。

直徑和深度都比一般的臉盆來的大一些,盆子本身是用整顆石頭下去挖空的,加上那顆不停轉動的石球及球下的底座(石頭做的),在沒有裝水時,普通人已經是很難抱得動,更何況是在盆子裝滿水的情況下,要移動它其難度不難想像。



它的位置就擺放在家裡的一角,安放在桌子上,桌子約莫 100 公分高



某天老爹晚上打電話找我閒聊,告訴我家裡發生一件詭異的事情,吃完晚餐,他們從外面散步回家後,發現地上忽然出現一大攤水,才看到整個石盆裡的水倒的乾乾淨淨的,乾淨到放個十元硬幣進去,剩下的水都沒有辦法淹過硬幣。

我們開始聊可能的原因:

「石盆會不會有破洞?」「本來也這樣想阿,可是重新裝水進去後,也沒有看到漏的地方阿」(台)
「會不會是地震還是家裡的狗撞到桌子?」「水也不會漏的這麼乾淨」(台)
「小偷?」「嘿阿,但是家裡都檢查過了,也沒有東西不見阿」(台)

想不到甚麼合理的解釋,這個話題就這樣結束了

接著,再和我老媽接上電話,聊到這件事,才知道原本我老爹在石盆裡還有放一顆一顆的佛珠(大顆的那種木製佛珠),因為放在水裏面已經有一段時間,表面都發霉了,所以我爸在出門前就先把所有的佛珠從水裡撿起來丟到垃圾桶裡了...

最後再打電話給我爸,聊到佛珠的事情,問他後續的動作

「就再從垃圾桶撿起來,一顆一顆的洗乾淨再放回去」(笑)

現在,它還是待在原來的位置上,石頭繼續不停的轉阿轉,裏面的水也再沒有少過 ;)