2/28/2012

2/05/2012

簡單好用的LIST之C語言實作

LIST用時方很少

撰寫程式時,多少都會用到一些串列、佇列等資料結構,有的程式語言會提供相關的實作,很容易就可以取用,相較之下,C language的使用者在這方面就比較麻煩。老練的C language程式設計師討生活的工具箱裡,都會有這方面的程式碼,以備不時之需。在open source的領域裡,也有不少高手提供這方面的函式庫。如果有需要搭配搜尋、排序的演算法,SimCList會是一個不錯的選擇,它的優點是使用方便,容易上手,速度也不錯,且授權方式採用極為友善的BSD license;倘若僅需要用到單純的list、stack、FIFO時,FreeBSD核心中的相關程式碼片段就可立即派上用場。其實Linux核心中也有功能相似的實作,較之前者可說各有勝場,只是Linux核心採用GPL授權,使用上需要多加斟酌。FreeBSD的List與Queue實作,位於sys/queue.h。

2/01/2012

3分鐘Git入門

何謂Git
Git是一個版本控制系統。效能優異,管理眾多檔案時,速度都能保持一定水準。使用時,無須連結至特定伺服器。大多數情況下,只要熟悉幾個指令,就能輕鬆上手。

Git單機使用流程
這裡指的「單機」意思是「單人」,不考慮多人協同工作的情形。不過,由於Git採取分散式架構的緣故,熟悉單人使用環境後,應可輕鬆軟換到多人協同工作的模式。簡單來說,Git單機使用流程如下:
  • 將目錄納入Git控制
  • 將目錄下的檔案納入Git管理
  • 提交變更的檔案內容

1/21/2012

lwIP網路卡驅動程式撰寫

lwIP網路卡驅動程式主要以輪詢模式(polling mode)運作。使用者將網路卡介面(network interface)透過netif_add()添加至lwIP後,其生命週期便由lwIP接管,之後只要在主程式迴圈(main program loop)中,按時輪詢網路卡驅動程式,將接收到的封包派送至通訊協定堆疊即可。驅動程式撰寫者,只需要專注於提供與lwIP相容之驅動程式介面即可。

11/17/2011

如何正確停止「live555 RTSP串流伺服器」

在前一篇文章裡,我介紹如何利用live555撰寫RTSP串流伺服器。文章的原始碼範例,並無針對一些例外訊號例如:「Ctrl+C(SIGINT)」進行捕捉處理。 在Linux中,這些例外訊號若沒有處理,其預設行為將是立刻終止程式,進而導致資源遺漏(resource leak)。
在Linux裡,我們可以透過signal()於程式中設立處理常式(signal handler),於對應之處理常式中,我們將可正確地停止RTSP伺服器。

11/06/2011

YAML簡介

什麼是YAML
YAML是YAML Ain't Markup Language的遞迴縮寫(一種來自Opensource界的奇怪幽默,如果你懂,你就...)。顧名思義,它設計的目的是作為表達、傳遞資料的一種資料描述方式(data serialization language)。與XML或類似的用途的語言相比,它著重於資料於人們的可(易)閱度讀性。
例如,以下兩個YAML的例子:
--- # 最喜愛的電影
- Casablanca
- North by Northwest
- Notorious
-
  name: Mark McGwire
  hr:   65
  avg:  0.278
-
  name: Sammy Sosa
  hr:   63
  avg:  0.288

11/04/2011

移植lwIP至U-Boot

U-Boot是嵌入式系統上被廣為運用的boot loader,它擁有極為活躍的開發社群,也支援許多不同類型的CPU核心架構。U-Boot目前並不支援完整的TCP/IP,僅有限度地支援TFTP,方便開發者上傳韌體或是網路開機(BOOTP)。U-Boot身為boot loader非嵌入式作業系統,依據開放原始碼社群秉持地「精簡就是美」原則,不支援TCP/IP是可以理解的。萬一真的需要網路功能,移植一套完整的TCP/IP協定堆疊的任務雖然富有挑戰性,實務上亦是可行之道。

lightweight IP(lwIP)是一個輕巧的開放原始碼之TCP/IP通訊協定之實作。lwIP首先由Adam Dunkels發表,目前則是以Kieran Mansley為計畫主持人,帶領開放原始碼社群進行該專案的維護與開發。
目前lwIP已實做的協定如下:
  • IP (Internet Protocol) including packet forwarding over multiple network interfaces
  • ICMP (Internet Control Message Protocol) for network maintenance and debugging
  • IGMP (Internet Group Management Protocol) for multicast traffic management
  • UDP (User Datagram Protocol) including experimental UDP-lite extensions
  • TCP (Transmission Control Protocol) with congestion control, RTT estimation and fast recovery/fast retransmit
  • Raw/native API for enhanced performance
  • DNS (Domain names resolver)
  • SNMP (Simple Network Management Protocol)
  • DHCP (Dynamic Host Configuration Protocol)
  • AUTOIP (for IPv4, conform with RFC 3927)
  • PPP (Point-to-Point Protocol)
  • ARP (Address Resolution Protocol) for Ethernet
  • Optional Berkeley-like socket API 
lwIP設計理念主要是希望於支援TCP/IP協定的同時,於執行時期也能精簡記憶體之運用,以達成支援小型的嵌入式裝置、平台或即時作業系統(RTOS)的目標;除此之外,lwIP也已經移植到眾多RTOS平台上,例如:eCos...等等。由此這些特性來看,使用lwIP搭配U-Boot是一個好的選擇。

9/04/2011

How to Install Ubuntu11.04 on Mac mini

This guide will explain how to install Ubuntu 11.04 on an external USB HDD.
  1. Download and install rEFIt under OSX.
  2. Insert Ubuntu Installation CD to an external USB CD drive.
  3. Reboot and hold Alt key to boot from the CD drive.
  4. Before installing Ubuntu, press F6 and select each options except the last one.
  5. Some options, noapci nopic nomodeset, should be turned off otherwise Linux will halt during the installation.There options would be disabled as well after the installation.
  6. Install Ubuntu on the USB HDD drive and do remember to install grub on the USB HDD as well.
  7. After the first reboot of installation, rEFIt should detect Linux.
  8. Choice to boot from Linux, GRUB will be loaded.
  9. Press "E" to edit boot options of GRUB.
  10. Find and add options to Linux boot arguments:
    linux /boot/vmlinuz-2.6.32-24-generic \
    root=UUID=xxxx-xxx-xxx-xxxx ro quiet \
    nosplash noapci nopci nomodeset reboot=apci
    
    Press Ctrl+X to boot Ubuntu after the modification.
  11. Install NVIDIA proprietary driver to enable 3D/OpenGL.
  12. Enjoy Ubuntu 11.04.

9/03/2011

How to transfer Ununtu11.04/Pandaboard to USB HDD

The pre-built Ubuntu 11.04/Pandaboard image is designed to be installed on a SD card. It could be transfer to the USB HDD with some extra efforts. Typically, a bootable OMAP4/Ubuntu SD card contains two partitions: boot and rootfs. Only rootfs should immigrate to a USB drive since Pandaboard requires booting form SD card.
  1. Prepares a bootable Ubuntu11.04 SD card. howto
  2. Create a ext3/4 partition on a USB HDD labeled "ubuntu".
  3. # /dev/sdXX should be the partition to be formatted,
    # for example /dev/sdc2
    $ sudo mkfs.ext3 -L ubuntu /dev/sdXX
    
  4. Copy rootfs on the SD card to USB HDD
  5. # Suppose USB is mounted on /mnt/ubuntu
    # and rootfs of SD is on /mnt/sd
    $ cd /mnt/ubuntu
    $ sudo cp -a /mnt/sd/* .
    
  6. Boot from SD card
  7. In order to mount USB HDD as rootfs, It'd update parameters that passed to the kernel. The configuration file is located at /boot/boot.script
    $ sudo vi /boot/boot.script
    
    You'd find bootargs have something like this:
    root=UUID=XXXX-XXXX-XXXX-XXXX
    
    Replace it to
    root=LABEL=ubuntu
    
    Then update boot.scr for uboot using:
    $ sudo flash-kernel
    
  8. Reboot it and Ubuntu should use USB HDD as root filesystem. :)

8/31/2011

To install Ubuntu 11.04 on PandaBoard

1. Download a prebuilt Ubuntu 11.04 image from here.
2. Create a bootable SD card(capacity >= 4GB).
    zcat ubuntu-11.04-preinstalled-netbook-armel+omap4.img.gz | \
    sudo dd of=/dev/sdX
    ## sdX should be the actual device node of SD card
3. Bring up PandaBoard with the SD card and enjoy it.

6/28/2011

To cross-compile glib to arm-linux-gnueabi platform

Some variables should be given during configuration stage in order to cross-compile glib to ARM/linux platform using the tool chain(s) that come from Linaro or CodeSourcery.
> export glib_cv_stack_grows=no; \
  export glib_cv_uscore=no; \
  export ac_cv_func_posix_getpwuid_r=no; \
  export ac_cv_func_posix_getgrgid_r=no; \
  CFLAGS=-I$(TARGET_DIR)/usr/include \
  LDFLAGS=-L$(TARGET_DIR)/usr/lib \
  ./configure --host=arm-linux-gnueabi --prefix=$(TARGET_DIR)/usr

More information can be found at here.

6/25/2011

GObject 入門 (Part 7) - 發送與接收訊息

訊息發送系統(messaging system)是GObject system內建功能之一,它讓物件於事件發生時,用來發送訊息給其他註冊該訊息者。這樣的設計可以避免系統或物件過於耦合(coupling),大型系統裡常可見到這樣的設計(Mediator pattern)。


在GObject system裡,物件(GObject)可透過g_signal_new()或g_signal_newv()註冊新的信號;並以g_signal_emit()發送信號。爾後,經由g_signal_connect()即可連結(connect)或接收某物件發出的信號。

6/19/2011

Compressing Images into WebP format using libwebp

libwebp is a software implementation of WebP, a lossy compression picture format which is introduced by Google. It provides a set of lean APIs that are easy to encode and decode WebP images. libwebp comes with two demo program: cwebp and dwebp. It could use cwebp to transform JPEG/ PNG images into WebP format.  And dwebp takes decoding jobs in contrast.
cwebp is a good example to study encoder part of libwebp. Here is a handy class to do the same job.

WebP/HTTP Push on Google Chrome

Google Chrome browser, and it borther Chromium browser, seems the only web browser that supports WebP server push at this moment. Opera 11 can display WebP image frame by frame but not in server push mode according to my experiments. By the way, I found that Opera 11 cannot recognize MIME type: image/webp.

6/18/2011

JPEG/HTTP PUSH how-to

JPEG/HTTP server side push is done by adopting "multipart/x-mixed-replace" MIME type. More detail information could be found on Wikipedia:

HTTP server push
HTTP server push (also known as HTTP streaming) is a mechanism for sending data from a web server to a web browser. HTTP server push can be achieved through several mechanisms.
Generally the web server does not terminate a connection after response data has been served to a client. The web server leaves the connection open such that if an event is received, it can immediately be sent to one or multiple clients. Otherwise the data would have to be queued until the client's next request is received. Most web servers offer this functionality via CGI (e.g. Non-Parsed Headers scripts on Apache).
Another mechanism is related to a special MIME type called multipart/x-mixed-replace, which was introduced by Netscape in 1995. Web browsers would interpret this as a document changing whenever the server felt like pushing a new version to the client.[1] It is still supported by Firefox, Opera and Safari today, but ignored by Internet Explorer.[2] It can be applied to HTML documents, but also for streaming images in webcam applications.
The WHATWG Web Applications 1.0 proposal[3] included a mechanism to push content to the client. On September 1, 2006, the Opera web browser implemented this new experimental technology in a feature called "Server-Sent Events."[4][5] It is now being standardized as part of HTML5.[6] Another related part of HTML5 is the WebSockets API, which allows a web server and client to communicate over a full-duplex TCP connection. 

Streaming JPEG images over RTP using live555 streaming media

Live555 streaming media  is a software library that provides RTP/RTSP streaming features mainly. It supports many popular video and audio codecs. At this moment, JPEG is still the most popular lossy compression image format. It says that Live555 supports JPEG as well but not directly, see here, here and here. Live555 implements JPEG's RTP payload however it doesn't come with any JPEG parser. According to common  Live555 streaming media programming flow, a user that gonna to stream JPEG images through  it should(here):
(i) "JPEGVideoRTPSink", which will be fed by
(ii) a *subclass* of "JPEGVideoSource".

6/17/2011

To cross compile Live555 streaming media for ARM/Linux

To compile Live555 streaming media for ARM/Linux is quite easy.
It needs only few steps:
> cd live
> ./genMakefiles armlinux
> make

Pre-built binary package:
live.2011.06.16-dev-armlinux.tar.bz2

6/12/2011

使用live555 streaming media建立RTSP串流伺服器

Live555 Streaming Media是一套優秀的開放程式碼函示庫,擁有完整的RTSP/RTP實作,除了支援RTP over UDP外,尚支援RTP over RTSP以及RTP/RTSP over HTTP,可用於傳輸多種主流的影音壓縮格式如:H.264、MPEG4、MP3....等。知名的播放軟體VLC的串流功能就是基於此函式庫開發。
利用它我們只要短短幾行程式碼即可建立自己的串流伺服器。

6/11/2011

GObject 入門 (Part 6) - 宣告及實作介面

GObject system僅允許「單一繼承加上多重介面實作」的類別宣告方式。這種方式相信對熟悉Java或C#的人來說並不陌生,單一繼承的顧名思義是指一個類別僅能繼承自一種父類別,在這種物件模型下,有時會讓物件的抽象化變得比較麻煩。舉例來說:如果我們的想要將前幾篇短文提及的圖形(shape)系統導入畫圖的功能,讓Rectangle與Circle類別都能於顯示器上畫出形狀,最直覺的方式當然就是在Shape類別宣告一個方法,姑且命名為draw(),再由Rectangle與Circle類別分別改寫(override)該函式,即可輕鬆達到目的;倘若Shape類別與Rectangle、Circle類別是兩組人馬開發維護,而Rectangle、Circle類別開發小組無法自由修改Shape的定義,前述的方法就變得不可行,僅能設法於Rectangle、Circle類別分別宣告並實作draw函式,這樣一來draw()就無法擁有物件導向系統多型(polymorphism)的益處,喪失執行時期的動態連結(dynamic binding)能力。為了彌補這個缺點擺脫單一繼承的限制,GObject system讓使用者可以隨意添加多個介面(interface),交由類別實作之。在此,可將介面(interface)想像成特化的類別,它僅能宣告法方但不能包含類別資料,但亦擁有執行時期的類別驗證(RTTI, Runtime Type Inedtification)的能力。

6/09/2011

GObject 入門 (Part 5) - 存取物件屬性

一般來說,在C語言允許使用者直接存取資料結構(data structure)的成員(member),前提是使用者必須知道該資料結構的定義(definition),當資料被封裝起來時,使用者就必須可能就必須透過額外的介面存取。例如以下情況:
... ... ...

typedef struct _CirclePrivate CirclePrivate;

    ... ... ...

struct _Circle
{
    Shape parent;

    CirclePrivate* priv;
};

struct _CircleClass
{
    ShapeClass parent;
};

    ... ... ...

void  circle_set_radius(Circle* circle, guint radius);
guint circle_get_radius(Circle* circle);

    ... ... ...
在上段程式碼中,CirclePrivate僅提供型別的宣告(declaration)並不提供定義(definition),使用者無法直接存取priv變數的內容,面對此不公開(opaque)的資料結構,使用者被迫只能靠程式介面來存取資料內容(在上面的例子中就是circle_set_radius與circle_get_radius),如此一來原設計者就輕易達成資料封裝的目的。
GObject system實做了一個泛用的物件屬性讀寫機制(generic get/set mechanism for object properties),此機制可讓使用者在知道物件屬性的名稱的狀況下透過GObject的g_object_get_property讀取或以g_object_set_property寫入資料。這套機制很強大,但同時也容易令人卻步,因為如果你設計的類別要支援這個功能,將會需要額外撰寫不少如裹腳布般的程式碼,況且GObject system也沒有規定一定要實作此功能程式才能運作,像前幾篇短文(GObject 入門 Part2、Part3、Part4)中提出的範例並無相關實作亦能正常運行無誤,基於程式設計族群懶惰的天性,很多人就當沒這回事。是否一定要在專案中導入此功能個人覺得可以審慎評估,若是想要降低專案中各元件的耦合度(coupling degree)或是為將來方便撰寫其它程式語言連結(binding to other language)鋪路,此功能值得深思,像GStreamer架構中允許元件(plugin)於執行時期載入並動態設定參數的特性,依靠的就是GObject提供的功能。GStreamer將GLIb與GObject發揮得淋漓盡致,本身功能亦十分強大,將來會另有專題介紹。:)