2008年3月29日 星期六

8x51 起手式 -LED 跑馬燈

Standard
講到自動控制一定會提到『 8x51 系列』的應用,這系列的晶片在近二十幾年來已經被廣泛開發到爛掉,無處不見其縱影呀,從燈號控制、定時裝置到各種自動化的家電、工業產品,都可以找到它的存在。因此,凡是講到要學習自動控制的應用與設計,『 8x51 系列』可說是必學的項目。

這學期因為專題教授強烈的『口頭勸說』和為了順便湊畢業學分,就跑去選修了『 8x51 微處理機』的課程,重溫了以前零星的經驗。話說這堂課有多次實作的作業,過程中玩弄電路板和程式非常有意思。不過課程免不了從最簡單的 LED 跑馬燈開始教,雖然乏味但也是一個惡搞經驗的開始〔尤其是不依照老師要求時 :D〕。

這是第一次作業的電路示意圖〔圖的標示和真實腳位不一樣,請參考 8x51 的腳位定義資料。〕:


作業目標是讓 LED 燈號從第一個燈開始,每 0.2 秒變一次燈號,向左旋轉三圈後,再往右反方向旋轉三圈,如此以重覆動作跑下去。程式設計流程大致上是:




程式是用 ASM 寫的,原始程式碼和詳細註解如下:

MOV R0, #24 ; 設定切換 LED 次數:跑三圈共23次
; 因為包括起始燈號,所以要設定成 n+1 次
MOV A, #11111110B ; 以 bit 為單位,設 1 代表該腳位會輸出 5V 電壓
; 設 0 則腳位輸出 0V 電壓,會讓 LED 有電位差而亮燈
; 這裡設最右邊第一顆 LED 燈泡為起始燈

RUNL:
MOV P0, A ; 使用 A 的設定值來設定 P0 ,以控制 LED
CALL SLEEP ; 呼叫 SLEEP 副程式,暫停 0.2 秒
RL A ; 將燈泡設定值向左平移

DJNZ R0, RUNL ; R0=R0-1
; 然後判斷 R0是否為 0
; 若 R0!=0:
; 跳回 RUNL 直到LED 跑完三圈(R0-1=0)
; 若 R0=0則往下繼續執行

MOV R0, #24 ; 設定切換 LED 次數(n+1)
RR A ; 此時 LED 設定會停在最左邊第一個位置
; 將燈泡設定值向右平移


RUNR:
MOV P0, A ; 使用 A 的設定值來設定 P0 ,以控制 LED
CALL SLEEP ; 呼叫 SLEEP 副程式,暫停 0.2 秒
RR A ; 將燈泡設定值向右平移

DJNZ R0, RUNR ; R0=R0-1
; 然後判斷 R0是否為 0
; 若 R0!=0:
; 跳回 RUNL 直到LED 跑完三圈(R0-1=0)
; 若 R0=0則往下繼續執行

MOV R0, #24 ; 設定切換 LED 次數(n+1)
RL A ; 此時 LED 設定會停在最右邊第一個位置
; 將燈泡設定值向左平移

JMP RUNL ; 跳回 RUNL 重新一次循環

; 暫停流程之副程式
; 12 clocks = 1 cycle = 0.000001 seconds
; 1200000 clocks = 0.1 seconds,故 2400000 clocks = 0.2 seconds
; SLEEP 被設計成可以浪費 2340912 clocks,算法如下:
; 12 + [(12+24)*R2 + 24] * R1
; = 12 + 9180 * 255
; = 2340912 clocks (0.195076 seconds)
SLEEP:
MOV R1, #FFH ; 指令會消耗12 clocks
; 設定R1=255
SLEEP1:
MOV R2, #FFH ; MOV 指令會消耗12 clocks
; 設定R2=255

SLEEP2:
NOP ; 浪費掉 12 clocks
DJNZ R2, SLEEP2 ; DJNZ 指令會消耗24 clocks
; 重覆跑 SLEEP2,共 R2 次
DJNZ R1, SLEEP1 ; DJNZ 指令會消耗24 clocks
; 重覆跑 SLEEP1,共 R1 次
RET ; 副程式結束並返回主程式
END ; 程式結束


這程式很笨,沒有 Interrupt 的使用,所以用很單純的 NOP 去吃掉時間,而一般書上和同學都用三個 Rx 去實作 Delay 的函式,但我偏不想這麼做〔多耗一點記憶體感覺程式就不優雅了〕,所以多了一點點時間誤差也就算了,反正人也感覺不出來 :P。

後記

8x51 就像是縮小精簡版的 x86 一樣,關念其實差不太多,就算比較少接觸 8x51 但也不至於忘掉太多過去的經驗〔至少我還有持續去玩弄 x86 的程式〕。還有在 Interrupt 的使用其實並不複雜,只不過因為老師的作業要求,所以也就沒有使用中斷去解決 Timer 的問題。

另外,找不到好用的 Open Source 8x51 模擬器,只好每次都燒到晶片上測試,實在很累人。哪天有空有動力時,再來為自己寫套好用的 simulator。最近也研究了一下 8x51 的 Assemler 和 C Compiler ,下次再來筆記一下好了。:)

2008年3月17日 星期一

Hacking Huawei E220 HSDPA 3G 網路卡的裝置和相關連線訊息

Standard
3G、3.5G 這半年多來炒的沸沸揚揚,令誰都想去辦個門號一探究竟。不過,談各家電信業者的 3G 服務品質已經沒什麼意思,來 Hacking 一下 3G 網卡的裝置訊息似乎會有趣得多 :)。目前,各家業者的 3G 門號,都是搭配『 Huawei 』的網卡,尤其以『 E220 HSDPA USB Modem 』最為普遍,其小巧又乾淨的外型相當討喜,因此就選擇拿它來開刀。

如何在 Linux 上安裝 E220 就不多說了,任何人都能在 Google 找到不少文獻,比較值得注意的是,安裝過程中會出現三個令人迷惑的 device file〔ttyUSB0、ttyUSB1、ttyUSB2〕。經搜尋過網路上的資料和實地測試後,已經大概知道這三個 Device file 的用途:
  • ttyUSB0: 被當成一般 modem 通道使用,處理 3G 網路撥接用
  • ttyUSB1: 回傳相關的裝置和連線訊息
  • ttyUSB2: 放驅動程式的儲存裝置〔不確定〕。

如果你有將網卡裝起來,通常可以使用 pppd 透過 ttyUSB0 連線到 3G 網路,我想這部份就不用再多做解釋了。倒是 ttyUSB1 的部份比較特殊,會回傳一堆奇奇怪怪的 messages 〔可以使用 cat /dev/ttyUSB1 看到內容〕,而這些 messages code 又各是代表什麼意思,就相當令人好奇,當然,這也是這次 Hacking 的目的。 :D

經過一番測試後,整理了一些 ttyUSB1 回傳的狀況。

不論網路是否有連線,每固定一段時間就會回傳:
^BOOT:82907211,0,0,0,6
不過目前為止,還不了解此訊息的內容是什麼意思,有可能是裝置編號或是 firmware 的版本。


撥號連線後,就開始會回傳一些不一樣的訊息:

目前的網路模式:
^MODE:5,5
^MODE:5,4
其中 5 是代表 HSDPA , 4 是代表 WCDMA。而其他的 3、2、1 應該分別是 EDGE、GPRS、GSM,不過,大台北地區的 3G 基地臺相當完整,我還沒機會碰到有 3G 以下的模式,所以無法確定。


連線訊號強度:
^RSSI:8
其中的數字 8 即代表訊號的強弱,理論上 10 應該是最強,而 0則代表沒訊號〔目前還沒機會測試到〕。


然後有資料傳輸的相關資訊和統計〔每兩秒鐘更新一次〕:
^DSFLOWRPT:00000002,00000000,0000001A,0000000000000000,0000000000000034,0000BB80,0007D000
^DSFLOWRPT:00000004,00000000,00000000,0000000000000000,0000000000000034,0000BB80,0007D000
^DSFLOWRPT:00000006,00000000,00000000,0000000000000000,0000000000000034,0000BB80,0007D000
^DSFLOWRPT:00000008,00000000,00000000,0000000000000000,0000000000000034,0000BB80,0007D000
^DSFLOWRPT:0000000A,00000000,00000000,0000000000000000,0000000000000034,0000BB80,0007D000
^DSFLOWRPT:0000000C,00000000,00000000,0000000000000000,0000000000000034,0000BB80,0007D000

在『^DSFLOWRPT: 』之後,有七個段落的訊息,大致定義如下所示:
<secondspast>,<speedup>,<speeddown>,<tx>,<rx>,<unknown1>,<unknown2>

SecondsPast: 已連線的時間
SpeedUp: 上傳速率,單位是 Byte
SpeedDown: 下載速率,單位是 Byte
TX: 已傳送的資料量,單位是 Byte
RX: 已接收的資料量,單位是 Byte
Unknown1: 永遠是 BB80,換成十進位是 48000,猜測是某理論速率
Unknown1: 永遠是 7D000,換成十進位是 512000,猜測是某些定義


了解了這些訊息定義後稍做 Coding,就能夠寫出一個堪用的 3G 網路連線資訊顯示器了。可是非常慚愧的,雖然 3G 網卡的功能相當一個手機,除了可以上網之外,理論上還可以撥打電話、收發簡訊,但目前針對 E220 的了解卻還僅限於一些訊息格式的定義。或許有機會,還可以再多做一些 Hack,希望讓 3G 網卡的功能在 Linux 上也能完全發揮。 :)

2008年3月10日 星期一

讓我們偷看未來的 Graphical User Interfaces

Standard
說到 Graphical User Interfaces〔以下簡稱 GUI〕,就不能不提到『Apple Inc』的貢獻,其產品的推出確實一直為我們帶來很大的想像空間,尤其是『Apple Mac』推出之後,炫麗的 Dock 特效一度造成風潮,可以不難發現新一代的 GUI 早就已經開始悄悄萌芽。或許『特效』這個關鍵字會讓你想到一些知名的 3D Desktop Technology〔如:Compiz 和 Window Vista Aero〕,但在這邊我們並不會去探討它們,不過未來的 GUI 還是脫離不了 3D Technology 的範疇。

電腦 3D 技術發展至今,最近在基礎層面的應用也被許多人所關注,尤以 Mobile Device 上的動態更令人感興趣,像是 Apple iPhone 內廣為人知的特效就是一個例子。現在要介紹的一個 Open Source Project -『Clutter Toolkit』,就運用 OpenGL 技術提供一個效果十足的 GUI。以下是從 Clutter Toolkit 官方網站摘錄的一段簡介:
Clutter is an open source software library for creating fast, visually rich and animated graphical user interfaces.

Clutter uses OpenGL (and optionally OpenGL ES for use on Mobile and embedded platforms) for rendering but with an API which hides the underlying GL complexity from the developer. The Clutter API is intended to be easy to use, efficient and flexible.

Clutter Toolkit 提供一個快速且有豐富動畫特效的 GUI Library,讓程式人員可以很輕易的使用 Clutter API 去開發出一系列好用且具有科技質感的使用介面。若是更進一步結合觸控螢幕當 Input,操作易用性將大大提升,能讓使用者能有非常特別的操作感受。從官方『Clutter Blog』中就可以找到一些很炫的展示影片〔Clutter + Webkit on iphone〕:

http://www.clutter-project.org/blog/?p=46

未來的 GUI 很酷吧!另外,Clutter 如此易用的原因,是因為它被設計成可結合 GObject,所以可整合 Gtk+ 系列的操作,一般的程式人員不用懂太多 3D/OpenGL 的東西就能夠使用。

除此之外,前輩『Jserv』的 Keroro DE,就應用了 Clutter 相關技術做了些整合的設計,以提高使用者易用性。詳細關於 Keroro DE 的說明,可參考『Jserv's blog』和他即將在『OSDC.tw』的發表。

2008年3月8日 星期六

初探 Glib Programing - I/O 處理事件化『 g_io_channel』

Standard
C語言本身沒什麼困難,只要好好弄懂指標與記憶體位置之間的關係,大體上『應該』就算會 C 語言了。真正令人感到怯步的部份,反倒是藏身其中的各種演算法、資料結構和作業系統機制問題,要經過長年累月的 coding 才能盡數體會。

相信許多人都曾經歷過自己硬幹『串列』的美好時光,造這種基本的資料結構似乎也成為了寫 C 的樂趣之一。但是,你可曾想過哪一天寫 C Program 時,再也不需要自製串列結構、再也不用使用 select() /poll 去操作 I/O、再也不用怕處理 String 遺漏許多安全細節、再也… ,一切『原始』的結構和機制,如果都不用再自己去刻劃,這樣的輕鬆的一刻到來,會是多麼愉快呀!『Glib』的出現,使所有夢想得以成真,讓 C Program 的開發更容易、更簡潔有效率且更穩定安全,如果說 Glib 是 libc 的加強補完計畫也不為過!〔雖然少了很多 coding 的樂趣 :( 〕

Glib 的眾多包裝之中,『I/O 處理事件化』是一個很特別部份,我們可以等待 I/O 的回應而不需要再用到 select() + loop。只要用『 g_io_channel 』設定好 I/O watch 後,讓 Glib 自己觸發 R/W 的事件 handler 就可以了,就如同 gtk 中觸發各種事件一樣的簡單。

基本 I/O 事件的 handler 宣告和設計:

static gboolean
gio_in (GIOChannel *gio, GIOCondition condition, gpointer data)
{
GIOStatus ret;
GError *err = NULL;
gchar *msg;
gsize len;

/* 若 IO HUP,直接返回 */
if (condition & G_IO_HUP)
return FALSE;

/* 讀取 IO 的資料 */
ret = g_io_channel_read_line (gio, &msg, &len, NULL, &err);
if (ret == G_IO_STATUS_ERROR)
g_error ("Error reading: %s\n", err->message);

/* 顯示讀到的資料訊息 */
printf ("Read %u bytes: %s\n", len, msg);

g_free (msg);

/* 返回成功值 */
return TRUE;
}


此 handler 的目的,是當 I/O channel 有資料輸入更新時,g_io_channel 可以呼叫它並讀取資料。舉例來說,假設此 I/O 是個 socket,遠端如果有資料傳過來就會觸發 glib 事件,然後呼叫此 handler。

至於如何設定該 I/O channel 並將 handler 設定為觸發 callback,可參考這樣的寫法:

int main()
{
GMainLoop *loop;
/* IO channel 所需變數 */
GIOChannel *gio;
gsize len;
int sockfd;
struct sockaddr_un sa_un;

loop = g_main_loop_new(NULL, FALSE);

/* 建立 socket */
sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Cannot create socket!");
return 1;
}

/* 初始化 socket */
bzero(&sa_un, sizeof(sa_un));

/* 配置 socket */
sa_un.sun_family = AF_UNIX;
snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "/tmp/gio_demo.socket");

/* 連接 socket */
if (connect(sockfd, (struct sockaddr *) &sa_un, sizeof (sa_un)) < 0) {
printf("Cannot connect!");
return 1;
}

/* 使用 socket 的 file description 建立新 g_io_channel */
gio = g_io_channel_unix_new(sockfd);

/* 設定編碼 */
g_io_channel_set_encoding(gio, NULL, NULL);

/*
監聽 IO 事件,設定 gio_in() 為觸發時的 handler
G_IO_IN:當有資料進入 IO
G_IO_HUP:當 IO 已經關閉切斷
*/
g_io_add_watch(gio, G_IO_IN | G_IO_HUP, gio_in, NULL);

g_main_loop_run(loop);
return 0;
}


此範例使用 socket 當做 I/O,除了 socket 之外,凡是只要有 file description 的都可以使用 g_io_channel 做監聽和操作。

過去我們一般都使用 select() 設定 timeout 去等待 socket 的 IO 訊息,再用 fget()、fread()等方式取得訊昔,其程式碼相當繁複也不易表達。使用 g_io_channel 後,一切便豁然開朗,能減少許多 coding 和 debug 的時間。

當然, g_io_channel 的能力不只是這樣,你也可以透過它傳送 messages 輸出到 I/O 之中:

if (g_io_channel_write_chars(gio, "Test Message", -1, &len, NULL)==G_IO_STATUS_ERROR)
g_error("Error writing!");


更多 Glib IO Channel 的資料,可以在官方網站找到:
http://developer.gimp.org/api/2.0/glib/glib-IO-Channels.html

雖然 GTK+ 的種種實在是令人不敢恭維, Glib 卻出乎意料的被設計得相當好,其中各種包裝過後的 API 都非常實用,在效能上也令人無可挑惕,很難想像他們是同門師兄弟。:P

Glib 包括的 API 範圍非常廣,一時間也無法一一列舉,有興趣的人可多多瀏覽『 GLib Reference Manual

2008年3月4日 星期二

LXDE 近期動態

Standard
之前多次提到的 『LXDE 羽量級桌面環境』最近進展神速,除了 pcmanfm 的許多 bug 被修正之外,也添了不少新功能,其中最重要的就是 desktop-icon。這新的 desktop-icon 將提供桌面圖示功能,屬於 pcmanfm 的 branches 之一,目前已經成熟達到可用階段,即將被併回原本 pcmanfm 的主結構中。

在 session manager 的部份,lxsession 已經被重新設計過,現在可支援常見的關機、休眠、儲存執行狀態等功能,提供作業環境的許多必要管理機制。

而 LXPanel 裡的新網路監控外掛『 netstat 』也進入了實用測試階段,除了有線的網路裝置狀態之外,在無線網路的部份提供了更完整的支援,如 AP Scanning 等。如果沒有什麼意外,在下一版 release 就會預設使用此 plugin。

以下是 netstat plugin screenshot,不難由 screenshot 中可以猜到, netstat plugin 將是以取代 NetworkManager 為目標而設計,因為尚缺部份功能,目前仍在持續開發中:

Wireless Information

Encrypted AP

Cable Detect

AP Scanning



另外,由於 LXDE Project 近日得到了 ASUS EeePC 等捐贈,我們有更多機會在 EeePC 上測試 LXDE,所以將會針對 EeePC 此類 Mobile Device 做更多一系列的開發。


歡迎大家的參與, LXDE 將會持續努力向前走,提供使用者一個『飛快』的桌面環境!


後記

好睏。都不太清楚自己在寫什麼了,只憑著興奮的情緒硬撐開眼睛在亂寫!