2006/12/28

利用 SVG 建立 UI

SVG 拿來建 UI 其實有很多範例,這邊拿兩個來供各位參考。
「嵌在頁面裡」的時鐘
嵌在頁面裡的俄羅斯方塊

最近在思考想要用 XUL, SVG, AJax 等來建立 UI, 不過若考慮 RUI 的話,應該還是要用一般 HTML 而非 XUL.

網站備份

以前用過 httrack, 但是感覺參數太多,用沒二、三下就沒再用了,今天發現有 webhttrack, 當然它會順便安裝 httrack. 至於怎麼用?可以參考一下 /usr/share/httrack/lang.def 可以發現正體中文是第十四個,因此命令可以這樣下:

# /usr/lib/httrack/htsserver /usr/share/httrack/ path /var/www/htt lang 14

之後就可以透過網頁操作,至於網址,請注意上面執行後的訊息即得。感覺還不錯用,推薦。

圓剛 Volar 數位棒試用報告

跟圓剛的業務通了二、三回信後確認該公司的產品 Volar 數位棒(內部型號 A808)有 Linux driver, 就去買了二支。試用如下:
一、driver 在該公司技術頁面下,或從 此處下載
二、請遵照該公司關於 Linux 說明網頁的步驟及 FAQ 做。
三、安裝 mplayer, 及 dvb-utils 兩個套件。
四、執行命令 scan -x 0 /usr/share/doc/dvb-utils/examples/scan/dvb-t/tw-Taipei > ~/.mplayer/channels.conf
五、可能要編輯一下上面產生的 channels.conf,這個檔可以參考一下 comments
六、mplayer dvb://ch1 <-- ch1 是該檔第一欄位的頻道名稱

2006/12/26

Server Push

Server Push 技術存在已經很多年,主要有三個方法,第一種最古老的用法就是利用 HTTP Header 一直定期更新網頁。另外二種可以參考 http://xulplanet.com/tutorials/mozsdk/serverpush.php. 該文二種作法都需要 netscape 相容瀏覽器,也就是 IE 不支援。其中前一種是由 Netscape 制定的,利用 Content-type: multipart/x-mixed-replace 表頭,這種方法的CGI 比較方便撰寫。最後一種則是較新的 server socket.

這邊利用 perl 來實作第二種作法,若你的伺服器是 apache, 檔名要存成 nph- 開頭:

#!/usr/bin/perl
# 若 www server 是 apache,檔名要設定成 nph- 開頭
use File::Find;
use CGI qw/:push -nph/;
# turn off io buffering
$|=1;

my $Pictures = "/home/wade/Pictures";
my $sleep = 2;

print multipart_init(-boundary=>'--magicalboundarystring');
find (\&wanted, $Pictures);

sub wanted
{
my $f = $File::Find::name;
next unless $f =~ /\.jpe?g$/i;
if (open FILE, "$f") {
print multipart_start(-type=>"image/jpeg");
while () { print; }
close FILE;
}
else {
print multipart_start(-type=>"text/plain");
print "File: $f";
}
print multipart_end;
sleep $sleep;
}
exit 0;

2006/12/21

專案管理的免費軟體 dotproject

這兩天又突然想要架專案管理的軟體,之前架 egroupware 沒架成功,設定太複雜了,而 Xoops 早期玩過一陣,是還不錯用,不過印象停留在先前的使用經驗上,它並不怎麼適合專案管理,當然,遠遠超過一年沒用,是否現在還是如此不得而知。

有看到一套 Joomla 據說也不錯,不過我沒裝,就先試用 dotproject, 一裝就成功,因此就是它了。它的中文包要另外下載,而我的環境下還得改 modules/tasks/tasks.php,原來是
$tsql = "SELECT $select FROM $from $join WHERE $where" . 要改成
$tsql = "SELECT $select FROM ($from) $join WHERE $where" .

沒錯,就是差了個刮號。還有個更大的問題,不知道會不會有人問,安裝好之後我一開始不知道怎麼登入!當然看 source code 會知道,帳號是 admin, 密碼是 passwd。這邊就不多說了。這套軟體拿來給多人共同開發專案目前覺得還算 Ok, 希望大家使用愉快。

2006/12/20

UPnP Remote UI with vnc

UPnP remote ui 有一種實作方式是透過 VNC, 這在我思考 GUI/RUI 時也提供另一種解決方案。因此就拿來玩玩,有幾點心得分享:
.debian testing 的 vncserver 預設當然會讀 /etc/vnc.conf
.上述可以透過 $HOME/.vncrc 蓋過,因為預設的 vncStartup 是 /etc/X11/Xsession, 為了使用自己的畫面,改成 $HOME/.vnc/xstartup, 這一點是為了我們的特殊需求,照理說不必改。
.我自己有編譯 Embedded Mozilla, 因此可以讓它一啟動就是只有 Embedded Mozilla on X.

如此一來就可以用 directvnc 來做 GUI,也可以在遠端用 vncviewer 來做 RUI.

2006/12/01

firefox on directfb

After build the GtkDFB in Gtk on DirectFB, do as followings:

1. cd $PREFIX/src
2. get firefox-1.5.0.3 source
3. get TEL_Moz_Dfb_1_5_0_3_Nov17_patch1.dat, the gtkdfb patch for firefox 1.5.0.3
4. extract them(in $PREFIX/src, ie. in /usr/gtkdfb/src)
5. cd mozilla; patch -p0
6. create the .mozconfig
7. make -f client.mk build

很不幸,編譯的成功沒錯,我執行 TestGtkEmbed 也算「看得到畫面」,但是感覺就是「當掉」了,還得從別台登入 chvt # 到別的 vt 後再切回來,否則都不會有任何動作。<-- 不會動作不代表整台當掉了,希望您別太衝動重開機。

繼續玩玩看,若能跑得起來,那我就....打算開始...hehe....

2006/11/30

Digital Media Center - djmount+ushare

若您對 UPnP 有興趣,GeeXboX 是個不容您錯過的東西,上面中文部份應該全部是我翻譯的,若有誤請幫忙修正,加上 GeeXboX 是個非常活躍的產品,因此文件也常常更新,我是懶懶的,文件過時是正常的。
已初步完成djmount 與 ushare 的合併,不過這兩個套件原本就有點問題,接下來得思考下一步要不要來修正,問題如下:
一、有時 djmount 不會在啟動時很快找到 ushare 分享出來的內容
二、有時光 ls /mnt/av 就會等很久,這是因為它會發出 advertisement 等著回應
三、有時 djmount 會自己不動作

前兩個是 ushare 造成的,後一個是 djmount 來的,還有我覺得該改進之處:
四、i18n 似乎被我改得有問題
五、對 local 目錄的加減檔案應該立即公告週知
六、ushare 功能應該分成現行的指定目錄與全系統自動搜尋
七、ushare 應該將檔案分成三類,也就是更改其檔案架構
八、目前找網卡是以第一個找到的為準,應該修正成第一個非虛擬網卡,甚至是每個網卡各有一個 upnp 服務。
九、應該儘量照 upnp spec 實作,例如傳訊息時要對每張網卡都送。

最後說一下主要更動的內容:
一、libupnp 換成 1.4.1, 並修改 configure #28481 將 --disable-device 拿掉
二、./configure --enable-debug=no
三、主要修改 fuse_main.c, djfs.c, cds.c, 其中前兩個檔最重要

命令下法也有點兩者合一,但移除 ushare 讀 ushare.conf 的部份,例如:
./djmount [-d] /mnt/av -c /Media -o iocharset=big5

2006/11/29

今天看到一則報導,關於蓋婭理論 當然說這是理論有人可能不同意,不過我個人非常認同此說。有些事都有其極限,像若夠力丟出一個物體時,它會跑出地球的重力範圍,而不再被重力吸引回來,而關於膨脹中的宇宙是否會因為重力夠而再被吸回原形目前雖然傾向於不會(重力不夠),但是這也在說極限這件事。

地球到底能不能承受目前的生物(尤其指人類)?假設以整個生物體來看,人類會產生的廢氣,是不是已經到了就算現在減量也無法讓地球回復年輕了呢?哦是回復冷靜才對。假設人類整體表現的特性就算有人出面呼籲也無法挽回的地步,人類雖然無法查覺,地球是否已經反應出來了呢?

若照地球的表現(歷史)來看,將來最適合人居住的地方又會是哪裡呢?我是不是應該先搬去住比較好?

2006/11/22

Debian etch/testing no public key available A70DAF536070D3A1

這兩天在 apt-get update && apt-get dist-upgrade 發生下面錯誤訊息,雖然似乎系統照常運作,但是有警告總是心裡不舒服:
W: There are no public key available for the following key IDs:
A70DAF536070D3A1
W: You may want to run apt-get update to correct these problems

解決方法如下:
一、尋找
# gpg --keyserver wwwkeys.eu.pgp.net --recv A70DAF536070D3A1
這個動作要花點時間,請耐心等待,因為每台電腦與網路狀況不一,我是約等了三分鐘,這僅供參考。成功的話,訊息大概如下:
gpg: requesting key 6070D3A1 from hkp server wwwkeys.eu.pgp.net
gpg: key 6070D3A1: public key "Debian Archive Automatic Signing Key (4.0/etch) " imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg: imported: 1 <-- 有找到並下載

二、接著再下匯入系統的命令:
# gpg --armor --export A70DAF536070D3A1 | apt-key add -

三、更新套件資訊
接下來再下一次 apt-get update 即可。

2006/11/21

ushare & djmount 雙效合一?

昨天主要在思考 ushare & djmount 怎麼合併的事,假設以 djmount 為主,但是更改其目錄結構與語法,我假設是 djmount MOUNT_POINT dir1...,如 djmount /mnt/av /Media, 那麼:

/mnt/av/xxx 搬至 /mnt/av/remote, 另外把 dir1, dir2 放到 /mnt/av/local 下。這樣一來其他 Media Server 丟出來的都可以在 /mnt/av/remote 下找到,而 host 分享出來的則在 /mnt/av/local 下找到,Media Server 有變動也應該立即反應到 /mnt/av/remote 下,而對 /mnt/av/local 下的檔案操作則應立即透過 upnp 機制讓其他 MediaRenderer 知道。

為何要雙效合一?這只是希望 GeeXboX 加入 ushare 時的想法,另外兩份 code 重覆的地方將之精減。作法上可能先搬 source code, 後面再把他們未真正實作 upnp spec 的地方補上。

2006/11/17

UPnP 相關套件源碼研究

UPnP-application1117.pdf 這是我整理這幾天的源碼研究整理,有些是這邊缺少的,有些是這邊有卻被我刪掉的。

2006/11/16

directfb

這兩天本來想在 debian testing 上照著 Gtk on DirectFB(*) 的步驟做,卻發現需要重新編譯的套件太多了。我在猜,是有機會透過 Debian Backport 來改正此問題,不過後來還是試著利用 debootstrap 建立文中提到的 unstable 環境。在執行 debootstrap 時遇到一個小小的問題,就是我將 debootstrap 建在我的隨身硬碟上,這一點會讓 debootstrap 失敗,原因是預設的 mount option 裡有 nosuid, 改成 defaults 即可。剛執行完 debootstrap 時,可以考慮以下命令:
mount --bind /var/log/ debian-sid/var/log/
mount --bind /var/run/ debian-sid/var/run
mount --bind /var/cache/apt/ debian-sid/var/cache/apt/
mount --bind /var/lib/apt/ debian-sid/var/lib/apt/
mount --bind /tmp/ debian-sid/tmp/
mount --bind /proc/ debian-sid/proc/

而 chroot 的下法也可以考慮採下面的方式:
chroot debian-sid /usr/bin/env -i HOME=/root TERM=$TERM PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/gtkdfb/bin /bin/bash --login

在編譯 dfb 套件前,可以考慮執行 dpkg-reconfigure passwd, 這會讓整個系統使用者帳戶比較正常些。或許有人會比較喜歡透過 base-config 命令完成類似的事,僅供參考。

照著文件做遇到有一個小問題就是 gimp2.2.10 我竟然無法成功編譯,不過後來我改用 2.2.13 就解決。目前我在 unstable 系統上是可以執行 gimp, 不過滑鼠不會動。有空再來玩它。


註:這份文件一直在修改,先前我照著舊文件在 testing 記得是可以編譯完 gtk+ 的。不過反正只是測試,就照新的文件做。
註:其實我是看到有人丟出來 dfb for mozilla 的 patch 檔,心癢難搔之下,就先把環境先建好,希望哪天能把 mozilla build on dfb 弄出來。

2006/11/15

數位家庭產品初探 -- uPnP 內部 (3)

今天照著昨天的想法,翻看了 libupnp 的 UPnP_Programming_Guide.pdf,當然還回顧了一下 upnp device architecture, 及 upnp standards, 突然發現一件事,uPnP 沒定義 Control Point 這種 device!

會有「Control Point Device」我想是一場誤會,而不是 upnp org 漏掉了。因為它把「控制」放在像 renderer 上。以我看的 ushare 搭配 djmount 來說,ushare 當然是 server 沒錯,而 djmount 若當成 client 端,它也身兼 control point 的功能: 瀏覽內容、搜尋內容、取得內容、控制內容。這怎麼說呢?以 GeeXboX 裡採用 mplayer 搭配 djmount 來說,若你想「重頭播起」,是不是就是一種控制?至於其他三個功能就不言而知。

另外說要把控制點移成第三裝置這件事,網站上還看不到 v2.0 spec 有談到。因此若就 v1.0 來說,要控制像電燈、印表機這樣的機器,似乎責任落在 renderer 上,可見這個 renderer 是被我誤解最深的地方。因此接下來該需要思考的,是現有 v1.0 的各項裝置間的關係與其運作流程。

再來說明一下昨天 djmount 看的心得雖然已經列了當時的筆記,不過 djmount 本身也有提供類似 cds, cms 的功能其實也很正常,按照 upnp spec 上所提也確實如此。只是 djmount 把所謂的 cds, cms 以 filesystem 的方式呈現,這不止提供更彈性的作法,與其他工具的搭配就變得獨立開來,算是非常聰明的。

那麼,同樣的思考邏輯是否可以套用在 ushare 上呢?我的意思是,若我們把檔案放到其指定錄,應該即時傳送出去,也就是對檔案的操作應該等同於對 uPnP 的操作。或許這想法也有其困難性,或許只是沒人去思考而已。先保留著。

最後,ushare 與 djmount 有不少共同功能,以我們的需求而言,一個同時含有這兩個功能的系統是不是可以把源碼也合併呢?當然其源碼不怎麼相容,但是合併是不是就提供我上面所提問的解答呢?

2006/11/14

數位家庭產品初探 -- djmount

djmount 寫法跟 ushare 差異非常大,感覺它想通吃 c/c++ 的用心,不過造成我覺得兩份源碼不太相容(或說風格大不同)。另外,看半天有點累,因此明天或許先驗證 upnp 怎麼說的,再來看 libupnp. 我相信這兩個都要花不少時間。

content_dir 跟 ushare 的 cds 看來很像,不過分成 public(本檔) 與 private/protected 部份
UpnpSetMaxContentLength (MAX_CONTENT_LENGTH);

didl_object 怪了,跟 ushare 來比,似乎簡單不少,不過感覺 ushare 寫的比較易讀

djfs file system implementation for djmount

<mount> -+- devices
|
|- <devname> -+- .status -> ../.debug/<devname>/status
| |
| +- xxx -+- xxx
| | |- xxx
| | `- _search/
| |
| +- .metadata/ -+- xxx
| | `- xxx
| |
| `- _search/ -+- search_capabilities
| |- -+- ...
| `- ...
|
|- <devname>
|
`- .debug/

/*
* Warning : the libupnp API (UpnpOpenHttpGetEx,
* UpnpReadHttpGet ...) has strange prototypes for length
* and ranges : "int" is not sufficient for large files !
*/

UpnpOpenHttpGetEx(), UpnpReadHttpGet(), UpnpCloseHttpGet()


djmount 比較有「物件」的概念,這會是較優的寫法呢,還是讓源碼不易閱讀呢?
比較有關的檔除了上面的 device_list 之外,還有 service, upnp_util,共三個


device_list 這個檔跟 upnp 相關性還比較大些

UpnpSearchAsync(), UpnpDownloadUrlItem(), UpnpGetErrorMessage(), UpnpInit(), UpnpFinish(), UpnpGetServerIpAddress(), UpnpGetServerPort(), UpnpUnRegisterClient(), UpnpRegisterClient() <-- 這是 Control Point 在 EventHandlerCallback () 會看到底下的 event type UPNP_DISCOVERY_ADVERTISEMENT_ALIVE, UPNP_DISCOVERY_SEARCH_RESULT, UPNP_DISCOVERY_SEARCH_TIMEOUT, UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE, UPNP_CONTROL_ACTION_COMPLETE, UPNP_CONTROL_GET_VAR_COMPLETE. UPNP_EVENT_RECEIVED, UPNP_EVENT_SUBSCRIBE_COMPLETE, UPNP_EVENT_UNSUBSCRIBE_COMPLETE, UPNP_EVENT_RENEWAL_COMPLETE, UPNP_EVENT_AUTORENEWAL_FAILED, UPNP_EVENT_SUBSCRIPTION_EXPIRED, UPNP_EVENT_SUBSCRIPTION_REQUEST, UPNP_CONTROL_GET_VAR_REQUEST, UPNP_CONTROL_ACTION_REQUEST 後面三個會被忽略 upnp_util 裡則看到更多些

UPNP_DISCOVERY_ADVERTISEMENT_ALIVE,
UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE,
UPNP_DISCOVERY_SEARCH_RESULT,
UPNP_DISCOVERY_SEARCH_TIMEOUT,
/*
* SOAP Stuff
*/
UPNP_CONTROL_ACTION_REQUEST,
UPNP_CONTROL_ACTION_COMPLETE,
UPNP_CONTROL_GET_VAR_REQUEST,
UPNP_CONTROL_GET_VAR_COMPLETE,
/*
* GENA Stuff
*/
UPNP_EVENT_SUBSCRIPTION_REQUEST,
UPNP_EVENT_RECEIVED,
UPNP_EVENT_RENEWAL_COMPLETE,
UPNP_EVENT_SUBSCRIBE_COMPLETE,
UPNP_EVENT_UNSUBSCRIBE_COMPLETE,
UPNP_EVENT_AUTORENEWAL_FAILED,
UPNP_EVENT_SUBSCRIPTION_EXPIRED,

talloc 讓 ushare 嵌入到 GeeXboX 變得可行?

先把這段寫下來,以免忘記。
在看 djmount 時(雖然以前有看到,但沒細看、想想),看到 talloc(), 據說它的 performance 雖沒有 malloc() 好(-4%),但是 code size 較小, 而且可以嵌入 uclibc 的產品中。因此或許 djmount 就是因為這樣才能嵌進 GeeXboX 的也說不定。
另外我覺得很好奇的是 Busybox 為何可以?有機會也可以看個究竟。

數位家庭產品初探 -- ushare *.c

這邊只研究跟 upnp 相關的源碼,初看之下有幾個未照規範實作或我們期待實作未實作的功能:
一、Auto-IP
二、多個網卡的處理
三、Timeout(TTL) 與重送 UpnpSendAdvertisement()
四、未提供與 hardware pnp 配合的功能,例如插入 usb disk 之類的。
五、檔案僅就附檔名分析卻未分析其內容

而用到 libupnp 的部份大致為:
UpnpEnableWebserver(), UpnpSetVirtualDirCallbacks(), UpnpAddVirtualDir(), UpnpRegisterRootDevice2(), UpnpSendAdvertisement(), UpnpAddToActionResponse(), UpnpUnRegisterRootDevice(), UpnpFinish(), UpnpInit(), UpnpGetServerPort(), UpnpGetServerIpAddress()
  • cds.c: Content Directory Service
看得出來支援四個 actions
#define SERVICE_CDS_ACTION_SEARCH_CAPS "GetSearchCapabilities"
#define SERVICE_CDS_ACTION_SORT_CAPS "GetSortCapabilities"
#define SERVICE_CDS_ACTION_UPDATE_ID "GetSystemUpdateID"
#define SERVICE_CDS_ACTION_BROWSE "Browse"

struct service_action_t cds_service_actions[] = {
{ SERVICE_CDS_ACTION_SEARCH_CAPS, cds_get_search_capabilities },
{ SERVICE_CDS_ACTION_SORT_CAPS, cds_get_sort_capabilities },
{ SERVICE_CDS_ACTION_UPDATE_ID, cds_get_system_update_id },
{ SERVICE_CDS_ACTION_BROWSE, cds_browse },
{ NULL, NULL }
};

#define SERVICE_CDS_ARG_SEARCH_CAPS "SearchCaps"
#define SERVICE_CDS_ARG_SORT_CAPS "SortCaps"
#define SERVICE_CDS_ARG_UPDATE_ID "Id"
#define SERVICE_CDS_ARG_START_INDEX "StartingIndex"
#define SERVICE_CDS_ARG_REQUEST_COUNT "RequestedCount"
#define SERVICE_CDS_ARG_OBJECT_ID "ObjectID"
#define SERVICE_CDS_ARG_FILTER "Filter"
#define SERVICE_CDS_ARG_BROWSE_FLAG "BrowseFlag"
#define SERVICE_CDS_ARG_SORT_CRIT "SortCriteria"
#define SERVICE_CDS_ROOT_OBJECT_ID "0"
#define SERVICE_CDS_BROWSE_METADATA "BrowseMetadata"
#define SERVICE_CDS_BROWSE_CHILDREN "BrowseDirectChildren"
#define SERVICE_CDS_DIDL_RESULT "Result"
#define SERVICE_CDS_DIDL_NUM_RETURNED "NumberReturned"
#define SERVICE_CDS_DIDL_TOTAL_MATCH "TotalMatches"
#define SERVICE_CDS_DIDL_UPDATE_ID "UpdateID"
還有一堆跟 DIDL 有關的變數,如 DIDL_NAMESPACE
其中 DIDL 是數位資料內部 buffer 的表示法,是 xml 格式,因此有 header, footer, tag, param, value, item 等等。

cds_get_search_capabilities(): upnp_add_response(SERVICE_CDS_ARG_SEARCH_CAPS)
cds_get_sort_capabilities(): upnp_add_response(SERVICE_CDS_ARG_SORT_CAPS)
cds_get_system_update_id (): upnp_add_response (SERVICE_CDS_ARG_UPDATE_ID, SERVICE_CDS_ROOT_OBJECT_ID)
以上是簡單的,複雜的也是處理 buffer 之後再叫用類似的函數與參數,如
upnp_add_response (SERVICE_CDS_DIDL_RESULT)


  • cms.c: Connection Management Service
#define SERVICE_CMS_ACTION_PROT_INFO "GetProtocolInfo"
#define SERVICE_CMS_ACTION_CON_ID "GetCurrentConnectionIDs"
#define SERVICE_CMS_ACTION_CON_INFO "GetCurrentConnectionInfo"

struct service_action_t cms_service_actions[] = {
{ SERVICE_CMS_ACTION_PROT_INFO, cms_get_protocol_info },
{ SERVICE_CMS_ACTION_CON_ID, cms_get_current_connection_ids },
{ SERVICE_CMS_ACTION_CON_INFO, cms_get_current_connection_info },
{ NULL, NULL }
}; <-- 只有三個 action

#define SERVICE_CMS_ARG_SOURCE "Source"
#define SERVICE_CMS_ARG_SINK "Sink"
#define SERVICE_CMS_ARG_CONNECTION_IDS "ConnectionIDs"
#define SERVICE_CMS_ARG_CONNECTION_ID "ConnectionID"
#define SERVICE_CMS_ARG_RCS_ID "RcsID"
#define SERVICE_CMS_ARG_TRANSPORT_ID "AVTransportID"
#define SERVICE_CMS_ARG_PROT_INFO "ProtocolInfo"
#define SERVICE_CMS_ARG_PEER_CON_MANAGER "PeerConnectionManager"
#define SERVICE_CMS_ARG_PEER_CON_ID "PeerConnectionID"
#define SERVICE_CMS_ARG_DIRECTION "Direction"
#define SERVICE_CMS_ARG_STATUS "Status"
#define SERVICE_CMS_DEFAULT_CON_ID "0"
#define SERVICE_CMS_UNKNOW_ID "-1"
#define SERVICE_CMS_OUTPUT "Output"
#define SERVICE_CMS_STATUS_OK "OK"

. 看來 upnp_add_response() 是對事件的處理,本檔也只定義了那三個 action 相對應的函式
. cms_get_protocol_info() 等於是把 Mime type list 串起來傳回去
. 下面第二行很特別:
upnp_add_response (event, SERVICE_CMS_ARG_SOURCE, respText);
upnp_add_response (event, SERVICE_CMS_ARG_SINK, "");
. cms_get_current_connection_ids(): upnp_add_response (event, SERVICE_CMS_ARG_CONNECTION_IDS, ""); <-- 後面這個 "" 應該再探究 . cms_get_current_connection_info() 有空再來研究這個比較有趣的 action:

upnp_add_response (event, SERVICE_CMS_ARG_CONNECTION_ID, SERVICE_CMS_DEFAULT_CON_ID);
upnp_add_response (event, SERVICE_CMS_ARG_RCS_ID, SERVICE_CMS_UNKNOW_ID);
upnp_add_response (event, SERVICE_CMS_ARG_TRANSPORT_ID, SERVICE_CMS_UNKNOW_ID);
while (list->extension) {
upnp_add_response (event, SERVICE_CMS_ARG_PROT_INFO, list->protocol);
list++;
}

upnp_add_response (event, SERVICE_CMS_ARG_PEER_CON_MANAGER, "");
upnp_add_response (event, SERVICE_CMS_ARG_PEER_CON_ID, SERVICE_CMS_UNKNOW_ID);
upnp_add_response (event, SERVICE_CMS_ARG_DIRECTION, SERVICE_CMS_OUTPUT);
upnp_add_response (event, SERVICE_CMS_ARG_STATUS, SERVICE_CMS_STATUS_OK);


  • msr.c
這個檔很奇怪,先寫下提供的 service 就好

struct service_action_t msr_service_actions[] = {
{ SERVICE_MSR_ACTION_IS_AUTHORIZED, msr_is_authorized },
{ SERVICE_MSR_ACTION_REGISTER_DEVICE, msr_register_device },
{ SERVICE_MSR_ACTION_IS_VALIDATED, msr_is_validated },
{ NULL, NULL }
};

  • http.c 拿來研究 embedded web server 還不錯
struct UpnpVirtualDirCallbacks virtual_dir_callbacks = {
http_get_info,
http_open, <-- 這兩個函數會用到 metadata.c 的函數,應該研究 upnp_entry upnp_id = atoi (strrchr (filename, '/') + 1); upnp_get_entry (ut->root_entry, upnp_id);
http_read,
http_write,
http_seek,
http_close
};
struct web_file_t {
char *fullpath;
size_t pos;
enum {
FILE_LOCAL,
FILE_MEMORY
} type;
union {
struct {
int fd;
struct upnp_entry_t *entry;
} local;
struct {
char *contents;
size_t len;
} memory;
} detail;
};

  • metadata.c: CDS Metadata DB
我知道的是在 djmount 會產生所謂的 metadata, 看來這東西很重要,而在源碼裡,這個檔好像是內部資料結構與 xml 的轉接橋樑, 這邊所謂的內部資料指的是「多媒體檔案」, 有空再來看

mime.c: media file MIME-type association
#define UPNP_VIDEO "object.item.videoItem.movie"
#define UPNP_AUDIO "object.item.audioItem.musicTrack"
#define UPNP_PHOTO "object.item.imageItem.photo"
#define UPNP_PLAYLIST "object.item.playlistItem"
#define UPNP_TEXT "object.item.textItem" <-- 純文字是當歌詞用? 其他的就不多說了,ushare 支援的格式非常多,看來只是純分析檔尾而已
  • presentation.c: UPnP Presentation Page

#define CGI_ACTION "action="
#define CGI_ACTION_ADD "add"
#define CGI_ACTION_DEL "del"
#define CGI_ACTION_REFRESH "refresh"
#define CGI_PATH "path"
#define CGI_SHARE "share"
看來所謂 presentation 跟執行 cgi 沒兩樣,但是它是 html 而非 xml


  • services.c: UPnP services

static struct service_t services[] = {
{ CDS_SERVICE_ID, CDS_SERVICE_TYPE, cds_service_actions },
{ CMS_SERVICE_ID, CMS_SERVICE_TYPE, cms_service_actions },
{ MSR_SERVICE_ID, MSR_SERVICE_TYPE, msr_service_actions },
{ NULL, NULL, NULL }
};

這邊定義了像 upnp_add_response() 這個常見的函式,此外有
find_service_action(), upnp_get_ui4(), upnp_get_string() <-- 這個是分析 xml 格式的 request
  • ushare.c: UPnP Media Server

比較精典的函式為: handle_action_request(), device_callback_event_handler()
後者有三個狀況:

case UPNP_CONTROL_ACTION_REQUEST:
handle_action_request ((struct Upnp_Action_Request *) event);
break;
case UPNP_CONTROL_ACTION_COMPLETE:
case UPNP_EVENT_SUBSCRIPTION_REQUEST:
case UPNP_CONTROL_GET_VAR_REQUEST:

上面是照抄,感覺好像有些該做的事沒去做,得查查 upnp 怎麼規範的

整個 ushare 流程如下:
. ushare_new() 初始化
. setup_i18n(); setup_iconv();
. 讀 config 檔
. 分析命令列
. 若 ushare 以 daemon 來跑,則啟動 syslog
. 在判斷有內容(多媒體檔及網卡)之後,會根據 MAC address create_udn()
. 取得 Ip address
. 若是 daemon, 則呼叫 daemon()
. 設定 signal (SIGINT, UPnPBreak); signal (SIGHUP, reload_config);
. init_upnp (ut): UpnpInit(), UpnpGetServerPort(), UpnpGetServerIpAddress(), UpnpEnableWebserver(), UpnpSetVirtualDirCallbacks(), UpnpAddVirtualDir(), UpnpRegisterRootDevice2(device_callback_event_handler), UpnpSendAdvertisement(1800)
比較怪異的是,竟然有「註冊->取消->再註冊」這樣的程序?而有效期限看來是 1800s
init_upnp() 就算是啟動真正的 upnp media server 服務了。可以參考 restart_upnp()
. build_metadata_list(ut)
. 進入等待 while (true) sleep (1000000); <-- 這樣寫好像怪怪的耶 11d13h46m40s?

數位家庭產品初探 -- ushare *.h

先列清單再摘重點說明,後續對研究源碼會有很大幫助

buffer.h cms.h http.h minmax.h services.h util_iconv.h
cds.h content.h metadata.h msr.h trace.h
cfgparser.h gettext.h mime.h presentation.h ushare.h

  • buffer.h: String buffer manipulation tools
定義 struct buffer_t {
char *buf;
size_t len;
size_t capacity; <-- 這較特別
};
及 buffer_new(), buffer_free(), buffer_append(), buffer_appendf() <-- format

  • cds.h: Content Directory Service
定義 CDS_DESCRIPTION, CDS_DESCRIPTION_LEN, CDS_LOCATION(/web/cds.xml), CDS_SERVICE_ID(urn:upnp-org:serviceId:ContentDirectory), CDS_SERVICE_TYPE(urn:schemas-upnp-org:service:ContentDirectory:1)

  • cfgparser.h: config file parser

  • cms.h: Connection Management Service
CMS_DESCRIPTION, CMS_DESCRIPTION_LEN, CMS_LOCATION(/web/cms.xml), CMS_SERVICE_ID(urn:upnp-org:serviceId:ConnectionManager), CMS_SERVICE_TYPE(urn:schemas-upnp-org:service:ConnectionManager:1)

  • content.h: content list
typedef struct content_list {
char **content;
int count;
} content_list; <-- 這寫法是個陣列
add_content(), del_content(指明 idx), free_content() <-- 整個 list,非單一

  • gettext.h: conditional use of GNU
簡單舉例 #define _(string) gettext (string)

  • http.h: Web Server handler

  • metadata.h: CDS Metadata DB
struct upnp_entry_t {
int id;
char *fullpath;
struct upnp_entry_t *parent;
int child_count;
struct upnp_entry_t **childs;
char *class;
char *protocol;
char *title;
char *url;
int size;
int fd;
};
typedef struct xml_convert_s {
char charac;
char *xml;
} xml_convert_t;
free_metadata_list(), build_metadata_list(), upnp_get_entry(), upnp_entry_free()

  • mime.h: media file MIME-type association
struct mime_type_t {
char *extension;
char *class;
char *protocol;
};

  • msr.h: Microsoft Registrar Service Routine
MSR_DESCRIPTION, MSR_DESCRIPTION_LEN, MSR_LOCATION "/web/msr.xml", MSR_SERVICE_ID "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar", MSR_SERVICE_TYPE "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"

  • presentation.h: UPnP Presentation Page
USHARE_PRESENTATION_PAGE "/web/ushare.html", PRESENTATION_PAGE_CONTENT_TYPE "text/html", USHARE_CGI "/web/ushare.cgi", process_cgi(), build_presentation_page()

  • services.h: UPnP services handler
struct service_action_t {
char *name;
bool (*function) (struct action_event_t *);
};
struct service_t {
char *id;
char *type;
struct service_action_t *actions;
};
#define SERVICE_CONTENT_TYPE "text/xml"
find_service_action(), upnp_add_response(), upnp_get_string(), upnp_get_ui4()

  • trace.h: log facility

  • ushare.h: UPnP Media Server
#define VIRTUAL_DIR "/web"
UPNP_DESCRIPTION,
struct ushare_t {
char *name;
char *interface;
content_list *contentlist;
struct upnp_entry_t *root_entry;
int nr_entries;
int init;
UpnpDevice_Handle dev;
char *udn;
char *ip;
unsigned short port;
struct buffer_t *presentation;
bool use_presentation;
bool verbose;
bool daemon;
};
struct action_event_t {
struct Upnp_Action_Request *request;
bool status;
struct service_t *service;
};

  • util_iconv.h: iconv string encoding utilities

2006/11/13

數位家庭產品初探 -- uPnP 內部 (2)

在前面 Auto-IP 的步驟之後,接下來就是 uPnP 通訊過程摘要。看完這段之後,後面會先看看 uShare, djmount 的源碼,以便了解其運作,再來研究 libupnp, 對照著這邊的步驟說明,這樣對整個 uPnP 的運作應該就會有較清楚的理解。

步驟一: Discovery(SSDP, 參考右圖)



狀況一:加入 Device
如下圖,當加入 Device 時,Device 應該發出 "Advertisement" 到 239.255.255.250:1900 公告週知。


狀況二:加入 Control Point.
如下圖,當有個 control point 裝置加入網路時,應該向現有網路廣播 "Search Request",裡頭會含該控制點感興趣的裝置種類,並因而取得相關裝置的回應(有可能多台)。若控制點想知道更多資訊,可以送含 Presentation 要求的 discovery 訊息出去,後面會討論。



有一點比較特別的是,若裝置正常離開此一家庭網路,應該送出「revoke」要求的 discovery 訊息來取消它先前廣播出去的資訊,此一步驟類似註冊與取消註冊。不過若無此正常步驟,控制點也應該定時更新。同理,若裝置的網址變動,亦應該公右週知。因此每一資訊應該含有「有效期限」資訊,相同的,控制點在有效期限過後應該更新之。

此外,若裝置或控制點有多個網路介面,應該同時對所有網路介面廣播,而且廣播訊息應該指定該網路介面的網址在 LOCATION 表頭中。當然像 TTL(default=4) 也不能少。而對於正常 IP(非 Auto-IP)應該附帶 IGMP Join 以便讓 multicast 封包穿越 Routers


步驟二:Description
如下圖,控制點在取得裝置(URL)後,可以透過該 URL 取得裝置描述檔,當然裝置要回應控制點的要求。若控制點對裝置較內部(詳細)的服務有興趣,這樣的交談可以採多次進行,控制點先取得裝置初步的 Device Description 後,再次取得進階的 Service Description.



步驟三:Control(SOAP)
如下圖,控制點可以在取得描述檔後,得知裝置提供的服務與動作,進而對裝置進行控制,其中至少包括「動作」要求,及變數的取得(或設定)要求。



步驟四:Eventing(GENA)
控制點先對感興趣的裝置做 "Subscribe" 動作,則該裝置狀態有改變時,會發出事件通知,利用 GENA 傳送 XML 內容給訂閱的控制點,該控制點因而可以即時得知最新狀態。如下圖,當 PDA 訂閱電視狀態後,從 PC 下 Power ON TV 動作後,電視在開機後應該通知 PDA 它最新的狀態。當然適當狀況下也應該取消訂閱動作。



步驟五:Presentation
如下圖,若裝置有提供控制頁面(Remote UI),則控制點可以直接瀏覽該頁面進而取得資訊或控制。

數位家庭產品初探 -- uPnP 內部 (1)

uPnP 用到的 protocol stack:













UPnP Vendor Defined
UPnP Forum Working Committee Defined
UPnP Device Architecture
HTTPMU
(Discovery)
[SSDP][GENA]
HTTPU
(Discovery)
[SSDP]



SOAP
(Control)
HTTP
(Description)
HTTP
[GENA(Event)]
UDPTCP
IP

一般動作有 discovery(SSDP), description, control, eventing(GENA), presentation.
uPnP 裝置簡單分成 controlled devices (又稱為 devices),及 controll points, 前者類似 server.
uPnP 裝置一定要具備 DHCP client 功能,

也因為 uPnP 裝置必然是在 IP 之上,定址是最開始的工作。若系統有 DHCP server, 則稱為 Managed network, 否則就是 unmanaged network. 當然在 unmanaged network 環境中,我們可以讓某一個 uPnP 裝置上實作 DHCP server。照文件上說明,Auto-IP 採用 169.254/16 範圍(zeroconf),排除前後各 256 個 IP 做為保留(參考 SSDP, RFC3927)。

Auto-IP 就簡單說一下,基本上是以 MAC address 為亂數種子來選取 169.254.1.0 到 169..254.254.255(再說一次,前後各 256 個 IP 列為保留不可使用)。選取位址後以 ARP probe 來測試該 Ip 是否使用中,若是則重覆選取與測試。

事實上,Auto-IP 是為了 unmanaged network,若 uPnP 裝置發現有 DHCP server 的存在,也必須在無連線需求下,切換到 managed network 工作狀態,有連線需求可保留某一段時間後再切換。
要找 DHCP server 可以每五分鐘(非固定)經由送 DHCPDISCOVER 去找是否有人回應 DHCPOFFER。

說到這裡,讓我想起 GeeXboX 並未遵守此項規定。

數位家庭產品初探 -- uPnP 裝置 IGD

uPnP 裝置列表 如下

裝置分類
  • 網路

額外服務

在 IGD DCP 裡定義了 Layer3Forwarding, WANCommonInterfaceConfig, WANPOTSLinkConfig, WANDSLLinkConfig, WANCableLinkConfig, WANEthernetLinkConfig, WANPPPConnection, WANIPConnection, LANHostConfigManagement,但是 linux-igd 套件只實作了 WANIPConnection 與 WANCommonInterfaceConfig.

至於文件裡 Sec. 3 定義的 XML Device Description 則參考 /etc/linuxigd/gatedesc.xml,源碼中也吐出不少 xml 格式的訊息。GetConnectionTypeInfo() 會吐出下面結果:

<u:GetConnectionTypeInfoResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewConnectionType>IP_Routed</NewConnectionType>
<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>
</u:GetConnectionTypeInfoResponse>


結論:Linux-IGD 這個套件對 Cable, PPP 等連線均未實作,目前似乎只有實作 IP 的連線而已。
這邊有個程式片斷用來說明 SDK 怎麼使用 serviceId,當然本套件也只有定義兩個 serviceId(WANIPConn1, WANCommonIFC1):

UpnpNotifyExt(deviceHandle, gateUDN, "urn:upnp-org:serviceId:WANIPConn1", propSet);

數位家庭產品初探 -- linux-IGD 源碼研究

全部檔案列表為: config.c gatedevice.c iptc.c main.c pmlist.c util.c

先從簡單看起,config.c, 這是採用正規表示法分析設定檔 /etc/upnpd.conf。其設定檔格式定義在 struct GLOBALS(globals.h) 裡。

char extInterfaceName[IFNAMSIZ]; // 對外網卡的名稱,如 eth1
char intInterfaceName[IFNAMSIZ]; // 對內網卡的名稱,如 eth0, 這兩個來自啟動命令
// 底下來自 /etc/upnpd.conf 的設定
int debug; // 0 無訊息輸出,1 輸出錯誤訊息至 syslog, 2 同 1 外含一般資訊,3 同 2 外含動態資訊
char iptables[50]; // iptables 命令的絕對路徑
char upstreamBitrate[10]; // 上傳 bitrate 限制
char downstreamBitrate[10]; // 下載 bitrate 限制
char forwardChainName[20]; // 放進 iptables forward chain 的名稱,例如 FORWARD
char preroutingChainName[20]; // 放進 iptables prerouting 的名稱,如 PREROUTING
int forwardRules; // 1 - 啟動 forward rules 嵌入 iptables 功能, 0 關閉
long int duration; // 0 - no duration
// SS 或 HH:MM - duration from the time of addition
// @SS 或 @HH:MM - expire mapping at the specified time of day
char descDocName[20];
char xmlPath[50];


main.c : 照源碼寫法,其命令語法 "upnpd [-f] EXT INT" 裡的 -f 位置不能亂動,這一點該注意。程式流程為:

.分析 /etc/upnpd.conf
.設定內/外部網卡
.取得內外部網卡的 Ip address
.對 daemon 的處理,這邊的寫法以前沒看過,可以參考一下。
.設定 umask(0) 之外,開啟 syslog "upnpd" <-- 在 /var/log/syslog 中含 upnpd
.呼叫 UpnpInit(intIpAddress,0) 做初始化 <-- 請見 libupnp
.呼叫 UpnpSetWebServerRootDir(g_vars.xmlPath) 設定 upnp 需要用到的 web server 目錄,其埠號是動態的,相關函數有 UpnpGetServerIpAddress(), UpnpGetServerPort()。若有異常則隨時用 UpnpFinish() 中斷 uPnP.
.接下來進入重頭戲,UpnpRegisterRootDevice() 註冊一個 uPnP Root Device
.StateTableInit() 會透過呼叫 UpnpDownloadXmlDoc() 自 web server 下載 gatedesc.xml, 請見 /etc/linuxigd/gatedesc.xml
.UpnpSendAdvertisement() 廣告週知,並進入聆聽中斷服務以便持續整個 IGD。
.聆聽中斷服務的方式是透過 #include <signal.h> 來完成,包含 SIGINT, SIGTERM, SIGUSR1
.最後正常結束(聆聽中斷),需要 UpnpUnRegisterRootDevice()+UpnpFinish();

以上整個邏輯不難,gatedevice.c 定義跟「device」有關的服務,例如 StateTableInit(), HandleSubscriptionRequest(), EventHandler() 定義了 UPNP_EVENT_SUBSCRIPTION_REQUEST, UPNP_CONTROL_GET_VAR_REQUEST, UPNP_CONTROL_ACTION_REQUEST 等,其他如 GetConnectionTypeInfo(), SetConnectionType(), GetNATRSIPStatus()

linux-igd 本身不支援 RSIP, 但 NAT 會。還有很多未列。請見 uPnP spec.(這一點我後續會再配合著發表心得) iptc.c 全部跟防火牆功能有關,應該搭配 iptables(libiptc) 的源碼來看。

pmlist.c 處理封包 port mapping 的函式 util.c 定義三個函式,get_sockfd(), GetIpAddressStr(), trace() 所以接下來我會研究一下 uPnP IGD 的 Spec.

數位家庭產品初探 -- libupnp 的應用 linux-IGD

linux-igd 是個類似防火牆軟體,這邊不討論編譯問題,而是討論使用問題,目前版本是 libupnp 1.4.1, linux-igd 0.95,請參考源碼中的 INSTALL 說明。後續我會對 linux-igd 源碼做分析。

首先你應該執行 "route add -net 239.0.0.0 netmask 255.0.0.0 eth0",其中的 eth0 是指對內通訊的網卡。順便再說明一下,linux-igd 應該跟防火牆軟體裝在一起,目前討論的都是搭配 iptables, 因此你應該修改 /etc/upnpd.conf 讓其 iptables_location = "/sbin/iptables" 指向正確的命令。另外,有點廢話的是,這軟體應該裝在具有「對內」與「對外」同時存在的網路環境上。


其實際執行範例如:
# upnpd eth1 eth0 <-- 前者是對外的網卡,後者是對內的網卡,若您只有一張網卡,或許是 # upnpd eth0 eth0:192.168 <-- 前者變成是撥接的對外網卡,eth0:192.168 是虛擬網卡用來對內部用 若你發現沒有 upnpd 這支 daemon 在背景跑的話,可以試試加上 '-f' 抑制它變成 daemon,如此可以立即得知錯誤訊息。

錯誤訊息應該會放在 /var/log/syslog 內,搜尋含 upnpd 的訊息對你會有幫助。

數位家庭產品初探 -- libupnp 相關套件

大家都知道數位家庭產品目前流行的是 DLNA, 而 DLNA 在底層的 protocol 方面則採 uPnP, 因此要談數位家庭就得研究 uPnP,而要談 uPnP 的開發就不得不談談 libupnp, 它可以用來寫各式跟 uPnP 的裝置(device)與服務(service),因此對數位家庭有興趣的人研究它是必要的。

libupnp 原本是 Intel 釋出的 GPL source code, 原先專案在 http://upnp.sf.net, 後來原團隊沒打算繼續發展,而由 Michael Pfeiffer 維護在 http://pupnp.sourceforge.net/ , 其版本始自 1.4.1。

先來寫目前我查到用 libupnp 建構出來的套件名稱列表,底下除了 ushare, djmount 外,是 debian testing 入選的套件,至於其他使用到的套件可以查上述 pupnp 網站,而最新版源碼亦可在該網站內找到。

gmediaserver: gMediaServer is a server for UPnP media players like the Netgear MP101, Linksys WMLS11B etc. It exports one ore more directories using the UPnP protocol so the mediaserver can browse through them and play audio or video files.


linux-igd: Linux UPnP Internet Gateway Device. This is a daemon that emulates Microsoft's Internet Connection Service (ICS). It implements the UPnP Internet Gateway Device specification (IGD) and allows UPnP aware clients, such as MSN Messenger to work properly from behind a NAT firewall.

wmaloader: firmware downloader for Linksys WMA11B media adapter. wmaloader is a simple program that can download filesystem images to the Linksys WMA11B. It performs the same function as the Windows XP/2000 Digital Media Adapter Application Loader (supplied with the original software) but can run on other operating systems. This allows the Linksys Wireless Media adapter to be booted from a linux system. It does *not* supply media files to the device (yet!) but even so it might prove useful to those who wish to experiment hacking the device.

2006/11/10

Firefox XUL

我一直很喜歡 Firefox, 其實對它了解不多,不過若以現在的眼光來看,我不會再以 Plugin 來做 Application 間的溝通工作。早期以 Plugin 來收發 message queue 是出於這樣會比較快速,但是事實上也讓移植性變得比較麻煩。也就是說,若我們可以透過 AJax 這種非同步的方式處理 UI 的呈現問題,其實速度會變得不那麼重要,但是更換版本就會變得較容易。另一方面,使用標準的方式也會讓其他事情變得較簡單,例如要呈現 RemoteUI 時,較容易彼此溝通與控制。

基於上述的思考,Firefox 有幾個東西對有興趣的人就變得很重要。

首先是 XUL, 這在 Firefox 裡已經有不少實際的 application on firefox 可以取得 source code, 比較常看到的是 chat, calculator, ftp 等。用 XUL 來寫基於 firefox 的應用程式,這樣會讓做 UI 的人比較麻煩,因為它並非標準 HTML/XML/Javascript,但是當我們對 XUL 的認知夠多時,要移轉也會較容易,而 XUL 的好處是 你不必叫出整個瀏覽器,而且,更重要的一點是新版的 firefox 已經整合 SVG 以及 sqlite, 這會讓我們在寫 XUL application 時有較佳的外觀與保密性,資料的維護也會比較容易。基於安全考量,似乎 firefox 不打算開放一般網頁使用 sqlite 及一些 XUL 能用的功能。

上面有提到 SVG 及 sqlite, 我想這個也是值得進一步研究的課題。但是我現在的工作跟 firefox 還沒什麼關係,沒什麼時間玩,就先寫下來供日後參考。而另一個重要課題是 AJax, 這雖然不像 DOM, Javascript 或 XUL, Plugin 等屬於專門的技術,而是一堆現在技術的整合,但是我想好好研究 AJax 是非常重要的,因為在 GUI 有必要與其他應用程式溝通時,可以達到非同步的效果非常重要。也就是,網頁的畫面可以不變動的情況下,就可以完成資料的取得,取得後再來更新畫面,在使用上會比較平順。而這一點用來取代原先 Plugin 應該就足夠了。畢竟透過 AJax 是以類似 CGI 的方式運作,可以做到目前網頁可以做到的事,也就是幾乎所有想做的都可以做到。當然,對像動畫效果的 GUI 無法像 flash 那麼好,但是那是「工具」的成熟度問題,其實我個人覺得 SVG/AJax 的搭配可以做到任何 flash 能做的事。

最後,firefox 比較缺的就是它目前還沒有辦法做到與X切割,若能靠 DirectFB 就能顯現 Firefox 的話,我想我就不會再考慮其他選擇了。也就是說,若你對 GUI 有興趣的話,DirectFB 也值得注意。directfb 其實已經整合進 Gtk 裡了,只是 Gtk 還無法與Xlib切割的很好,也希望 Gtk 能多多加油!

2006/11/08

怎麼利用 google 來工作?

google 是我非常喜歡的公司,以前曾有報導 web OS,這樣的觀念在目前已經被 web2.0(中文解釋) 淹沒了。現在也有非常多 web2.0 網站出現,是否會是另一個網路泡沫?先不管這個,我個人用最多的目前還停留在 google 推出的東西上,因此這邊寫下來我的想法。


搜尋: 這是最常用的功能。
gmail: 這個可以拿來當gmail 的多人討論事情的論壇功能,但是目前被下面的 google groups 取代,gmail 目前除了純粹拿來收信功能外,還可以用 gChat 來聊天,一般公司大概無法擋住它。
groups: 這個有點類似早期的 BBS 或者後來的 phpBBXoops ,用來建立論壇非常適合,而且最棒的是現在它也提供上傳檔案與建立網頁的功能。
網頁:一般放圖文並茂的內容,或許也拿來放檔案。
wiki : 通常讓大家一起編輯共同內容,翻成「共筆」,因此比較適合拿來放專業的東西。它提供上傳圖檔。可以在內容放圖片。
blog: 一般拿來發表日誌,有人看成是新聞,也算是八卦集中營。
行事曆: 可以讓人知道你的行事曆,對於團隊進行專案也非常有用
網路相簿: 剛開始成立時我有申請,後來沒用,被 google 收買應該有改進,放相簿應該不錯。
網路辦公室
: 適合放多人共用的文件。
翻譯: google 翻譯也不錯,除了可以翻譯文章,也可以翻譯網頁

搜尋就不多說了,與 gmail 這二項算是我最常用的,gmail 還可以用 gChat, 因為我個人不喜歡裝一些有的沒的,而公司通常會架防火牆擋 MSN,因此 gChat 也算非常好用的。

原本 groups 只能貼文章,後來慢慢把功能補好,可以指定重要議題置前,也可以上傳檔案,線上編輯網頁,對論壇功能而言已經非常好用了。但是我覺得還無法取代下面要說的網頁功能。google pages 提供方便的個人網頁,其編輯介面就是 web, 超級簡單,也可以上傳檔案,真的是非常值得推薦使用。至於 groups 提供的網頁功能,我覺得只是補強論壇文章原先只能貼文字的部份,不適合拿來當個人首頁用。

Wiki 本來就是共筆的功能,它較適合放專業技術的內容,而 blog 則適合放像日誌或新聞的內容,不過我發現 google blogger 也不錯用,可以編輯,只是 blog 較適合個人使用。也就是多人使用的話,groups 算是「討論」專用,而 wiki 適合拿來放多人產生的專業文件,結論等等。至於 blog 則發表個人的心得。行事曆則提供專案時程規劃。另外 google docs 則提供撰寫正式文件的地方,讓你可以轉成常見的 word 文件。事實上我個人還沒正式開始用 google docs 的功能。

以上是我認為可以利用 google 產品的地方,希望將來團隊在開發產品時能好好利用。

Sony Bravia STB 初探

先寫一封目前在玩的東西:
com port 設定為:
115200bps, 8N1, HFC/SFC =off/off

底下測試開機時間從供電到看到節目約 13 秒,而看到訊息是從 kernel 已經初始化完才開始看到,沒看到 bootloader 階段的訊息
開機訊息
.SOC Chip: STi5516-C 180MHz
.OS: OS20/ST-Lite: 2.10.04 (17:36:11 Aug 9 2004)
.系統建立時間:Jun 21 2006 at 10:11:33
.change channel 時間約 3 秒


關於選單在使用手冊已有載明,功能不多,很多時候,右鍵等於 "Ok"

目錄(Main Menu):
.最愛頻道表一
.最愛頻道表二
.節目表(channel list)
.電視節目指南(epg)
.設定

最愛頻道表、節目表、設定:
.半螢幕
.其風格有Sony風,在選單下方有可用按鍵指示,在 list 右方有是否可向上/下捲動的箭頭指引
.每頁顯示七個頻道

設定:
.全頻道搜尋: 約 90s
.快速搜尋: 約 45s
.手動搜尋
.顯示/隱藏頻道
.最愛頻道

電視節目指南:
.全螢幕
.一次顯示五個電視台
.只顯示「當前播放中」與「後續節目」兩個時段,而非「七天」或任意時段

OSD:切換頻道時的 OSD 非常醜

我的 wiki

Wiki 是一個寫心得的好地方,一直以來,我把 blog 當成寫日誌,而 wiki 當成寫心得,這樣的分法希望從今天起落實。也就是說把每日工作項目移至 blog,整理好的心得則貼在 wiki 上。web page, wiki, blog .... 之間的關係我會慢慢摸索。依賴 google 日益深入,到目前為止還沒有 M$ 給我的厭惡感,希望 google 能保持下去!

這封是以 email 張貼過來的,下面的簽名是我的 email 簽名檔。
--
自由的精靈, 狂想的空間
Free Spirit, Fantasy Space

慶祝開幕

父子同心 - 石門放風箏的路上,北海岸的休息站


今天為了申請 FON router, 上面說要提供 blog, 雖然不是強制的,但是 blog 本來也是很重要的啦。希望我能常常來此貼文。