2012年12月29日 星期六

Google Map一些可以注意的點

Google Map在使用上要注意,他並不是完全是分秒的格式,因為在地球儀上,使用的是六十進位,但是google map則是在分的部分使用六十進位,但是秒的部分卻是使用時進位,所以在解析NMEA格式的時候記得要單位轉換

另外常用的由兩個GPS點座標進行距離轉換的方式,單位是公尺
google.maps.geometry.spherical.computeDistanceBetween(p1, p2)/1000

另外一是zoom level的設定

var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = sw.lng();
var east = ne.lng();
var angle = east - west;
if (angle < 0) {
  angle += 360;
}
var zoom = Math.round(Math.log(pixelWidth * 360 / angle / GLOBE_WIDTH) / Math.LN2);

2012年12月27日 星期四

node.js

最近試驗了一下node.js跟翻閱了網路上的一些文章,發現non-blocking跟event loop/queue的作法有其好處,但是也有問題存在阿!!

過去因為是blocking的作法,如果遇到上傳檔案這種事情,一個process或者thread將會占用掉server一定的資源,至少在完成該動作前,該process/thread不會被釋放出來

反觀node.js的作法,卻是將動作放入event queue反覆取出處理,相對比較不佔用資源
但是這樣的好處卻要付出代價的,因為node.js的機制相對類似於cpu的排程,他並沒有同步或者等待的機制,這部分都要programmer自行處理,當然網路上也出現了一些libs來處理這些事。

不過反觀這樣的做法,很類似mysql一開始為了速度放棄了transaction,但是如果一旦transaction需求的重要性多過放棄transaction帶來的好處,就會引發開發上負面的效果

參考資料
http://www.nodebeginner.org/index-zh-tw.html


相關的libs:

seq

promise

Daily JS

2012年12月24日 星期一

告一段落

單車GSP logger分析程式告一段落,直接看影片吧,以後有空再把他補完

簡單補個參考資料
http://brooky.cc/2011/08/04/using-jquery-validation-plugin-for-form-validation/

2012年12月15日 星期六

jquery要注意的兩三事

wrap的使用:必須要將準備包裹的$(xxx)加入倒DOM中,不然是無法作用的
before/after跟append/prepend的差異:before/after將元素貼到<div></div>之後,比方$('div').after('<p>')變成<div></div><p>,若是append則是<div>data<p></div>

過去儘量不想在view內加上類似的程式碼,看來還是不可能的任務

參考資料
http://blog.bandit.co.nz/post/947175929/jquery-wrap-must-be-on-dom-object
http://www.dotblogs.com.tw/topcat/archive/2009/12/28/12702.aspx

2012年12月14日 星期五

web application開發疑惑

大約四五年沒認真一點開發web application,真的是一日千里,尤其JQuery應該是貢獻良多吧
隨著雲端,web application真的是爆炸性成長,再加上JQuery以及AJAX推波助瀾,可怕的html從簡單的顯示內容,搖身一變,變成可以開發應用程式的平台,瀏覽器當然也遠遠超出本來瀏覽的目的

可以看到JQuery儘量讓HTML跟事件分離,不用在HTML裡面放入一堆類似click事件,使得開發更有彈性,對於資料的取得也透過AJAX,不用每每需要資料就要在asp/php/jsp裡面塞入一堆資料到javascript codes當中,看起來是非常可怕的事情,以前一次融合兩種程式邏輯,用動態產生動態,真的是一場試煉

一個原本不是為了開發應用程式設計的東西,硬要裝上一些功能,就變成一場試煉,雖然JQuery以及AJAX將許多原本不可能變成可能,但是還是有些問題尚未解決,這是我認為web application及不上一般application開發的地方

沒有標準的widget,DOM本身並不是為了當widget開發出來,所以在操作上,必須將一些操作硬是搭配上去,讓屬性、事件顯得非常凌亂,連簡單的setText在很多元件上(我不知道適合用這個詞嗎?)都很欠缺

=========2013/2/18=========
體會到目前的業界好些狀況是JQuery/CSS跟AJAX已經是趨勢。使用JQuery的理由是本身JQuery吸收了許多瀏覽器不同屬性的操作方式,雖然還是因為CSS解釋有點不大一致,不過大體上已經好很多了。AJAX則是為了互動而設置的好處,壞處debug還是相當凌亂,有人靠瀏覽器的debugger,有人自行撰寫debug function。最好玩的是JQuery發展出來的GUI元件大多被捨棄不用,反過來自行發展GUI元件,因為大多認為他人寫的GUI元件不穩定,修改困難,不如自己從頭打造

目前javascript library一大堆,但是大多山頭林立,好似很難讓人相信很穩定

2012年12月11日 星期二

一些網頁元件

拜jquery以及ajax之賜,很快一些Web GUI如雨後春筍般地冒出,但是每個其實都要自己去評估,沒有完全一套的GUI是比較可惜的,但是也是好處。我比較偏好簡潔的風格(簡單說,希望在十分鐘內可以上手,最好coding只要一兩行),下面是幾個我survey過的GUI元件,做個紀錄

一般元件
Scrolling Table
http://www.htmldrive.net/items/demo/34/Pure-CSS-Scrollable-Table-with-Fixed-Header
Color Table
http://www.htmldrive.net/items/demo/33/Colorize-jQuery-Table-Plugin
List selector
http://harvesthq.github.com/chosen/
Loading Mask
http://code.google.com/p/jquery-loadmask/
JNotify
http://www.myjqueryplugins.com/jquery-plugin/jnotify

Calendar

Event Calendar
http://www.vissit.com/jquery-event-calendar-plugin-english-version
iCal Calendar
http://www.htmldrive.net/items/demo/568/astonishing-iCal-like-calendars-with-jQuery
Dojo Calendar
http://demos.dojotoolkit.org/demos/calendar/demo.html

我是想要一個簡單的Event Calendar,後來又回歸到jquery ui上面,

  • 第一個event calendar結合json,一定帶有event list,必須改code修正客製化
  • iCal基本上蠻簡潔陽春的
  • Dojo看demo很強大,但是要跟dojo的framework結合,效能不知如何,就不用了


ajax檔案上傳
uploadify
http://www.uploadify.com/
jquery upload demo
http://blueimp.github.com/jQuery-File-Upload/
plupload
http://www.plupload.com/example_queuewidget.php

如果只是要檔案上傳,很多可以用,甚至可以自己寫,但是如果要基本畫面,如process bar大概免費的舊這三個

  • uploadify最簡單,可惜要使用flash或者繳交5USD買HTML版本
  • jquery upload demo支援HTML 5,不錯,很可惜GUI很複雜
  • plupload支援多種平台,感覺很好,但是HTML 5畫面簡直是陽春,要自己重新設計一下


2012年12月8日 星期六

對google map的微辭

google map把持了資料,跟平台應用方式,這是我個人對google map不滿意的地方

google map的資料只能透過google map取得,換句話說,大多數對google map的操作都得透過google map api,這不只是google map服務而已,比方說,一般使用者沒辦法把google map製作成離線地圖,只能巴巴的等待google完成這項功能

google map在開發應用程式,很抱歉,你有幾個選擇,就是瀏覽器跟android,剩下的,很抱歉,你只能用半吊子的方式,比方說java要嵌入google map元件,官方並沒有,自己要想辦法,要用c++,那你只好內嵌一個瀏覽器,他的API平台是相當有限的

如果未來open map圖資足夠,我覺得大家跳到open map是一個好選項,畢竟目前google map一些其他強大的功能並不是大家都需要的,比方說街景跟室內3D,甚至於其他如水文之類的,應該就更少人用了

我個人不是反對google map,只是希望google map能夠更加的開放

2012年12月2日 星期日

javascript的迷思

可以看看javascript開發者對javascript現狀的評論www.josephjiang.com/presentation/OOJS/object-basic.html

個人認為是太多人認為javascript太好學,充斥了太多javascript的錯誤資訊,javascript的特色也太過於被濫用

最近我犯了一個錯誤,我想很多人如果比較熟悉C++ or Java之類,乃至於python這種語言都會犯的錯誤
var obj1 = new Person();
var obj2 = new Person();
var callbakcs={};
callbacks[obj1]=callback1;
callbacks[obj2]=callback2;
很簡單的想法就是想要為物件指定不同的callback function,結果不行,問題是所有callback function會指向callback2,理由是javascript並沒有替object做出唯一的key,javascript會呼叫toString()替代,所以obj1跟obj2會得到相同的字串
在C++是address,在java會由Object的method提供,ptyhon也不例外,例外的是javascript,真的替我上了一課XD

2012年11月30日 星期五

2012年11月27日 星期二

javascript is a(an) OO language?

推薦一本書,javascript patterns
http://shop.oreilly.com/product/9780596806767.do

不少專案在研究javascript如何實作繼承(inheritance)這件事情,者本書的第六章專門討論這個章節,有興趣的人也可以跑去研究coffeescript如何實做這件事情
我思考了這個議題的後續發展multiple inheritance三天,終於了解到了他跟類似C++/Java發展的差異性

看backbone.js跟prototye lib的時候,我一直懷疑,為何要包裝成這樣,感覺不如使用javascript來的直觀,效能稍微也比較差一點,但是仔細想想後,他們都有他們的道理,只能說用javascript來實作C++/Java的語意,實在有一定的難度

我得到的東西

  • javascript prototype, property生成的方式
  • C++/Java在多重繼承上面的考量,在multiple-interface跟multiple-inheritance的實作上的差異
  • javascript如何實作多重繼承(我自己弄了一個,就不野人獻曝了)


整體可以看出,javascript在彈性上面很方便,可是如果要實作多重繼承則是非常吃力,code reuse無法如C++/Java容易,反倒是用另外一種觀點(duck typing),反而來的輕鬆,這樣來說算不算OO呢?我覺得是見仁見智囉

2012年11月19日 星期一

Javascript is OOP?

這是個會引發"聖戰"之類的話題,我想這件事情留給有能力的人去回答,退而在此討論javascript"做得到"跟"做不到"的事情

is-a關係,很多人第一刻在繼承裡面學到的。我們說objC is a objP,也就是說可以把objC當成objP一樣對待,兒子應該跟老爸有相同的四肢構造。

可以先看底下的文章,解釋如何使用javascript的prototype完成繼承
http://peter.michaux.ca/articles/transitioning-from-java-classes-to-javascript-prototypes

首先要解釋的是javascript是duck type的程式語言,很多程式語言都是duck type,也就是一個物件看起來像是鴨子(特徵attributes),走路像鴨子(methods),那麼我們就認定他是一隻鴨子

javascript藉由prototype,隨時隨地可以將一個物件的屬性跟介面加入另外一個物件裡面,讓一個物件看起來像是另外一類的物件,比方說在上面peter給的範例實作了observer pattern,如果今天我有個物件擁有update方法,那我就看起來像是observer,真的是這樣嗎?所以要預防這種事情,絕對的方式是用instanceof來檢驗update方法真的來自observer。第二個問題,跟著如果併入另外一組物件的屬性跟介面(也有update)的時候,兩個function A跟B想要的是不同型態的參數,這時候呼叫的是哪一個update??似乎兩者都可以互通,這是duck type的特性
extends(WeatherModel, Observable);
extends(WeatherModel, Observable2);<=????????????????
function A(o:Observable);<=????????????????
function B(o:Observable2);<=????????????????
可以預期的是上面的程式碼可以順利運作(一定會呼叫某個物件的update,或者某個型態的update),但是未必如你所料

回頭來看java/C++,如果今天要在程式執行期間的實作一組介面,恐怕沒有辦法,你只能期待能不能從java Reflection或者C++的pointer跟強制轉型,擠出一點希望,但反過來說,是你可以確定的是不會讓一個不該屬於某個介面的物件放進一個不應該屬於那個型態的function之內(compile time)

OO上很重的一個觀念是is-a的體現,但兩者不同的做法沒有絕對的好壞,因為OO上is-a的解釋很寬廣。從上面可以看出來java/C++是strong type,所以在這種事情上給了某種保證,但是也失去了彈性,javascript獲取了彈性(duck type),但是也付出了某種代價。
OO的體現差異,上面提到的只是兩者之間在OO方面實作差異的冰山一角,希望能對大家在OO上面有進一步的體驗。

Peter的文章告訴我們不要從語言上面學習OO是個很重要的觀念,同時了解語言的差異在體現OO的特性上也很有幫助。對於學習OO觀念,或許從CRC卡上著手是個不錯的開始

可是也別太過極端,認為任何程式語言都可以實作OO,那恐怕是程度上的區別。不要被程式語言綁架了體現OO的作法,但一個程式語言號稱是OOP亦有他的道理

P.S. 網路上爬了一堆號稱javascript繼承實作的方式(甚至多重繼承),請仔細檢驗,是否能夠達成呼叫super class的constructor?是否能使用super class的variable?這往往跟我們直覺不大一樣,一旦在sub class/instance 呼叫了super class的method,其中帶有super class的variable,很快地會看到interpreter跟你抱怨,那個method不是一個function(奇怪吧!)
比方說下面這個網址的實作,至少就犯了兩三個錯誤
www.amirharel.com/2010/06/11/implementing-multiple-inheritance-in-javascript/

下面是一個例子,討論串中有它的問題
http://www.steinbit.org/words/programming/multiple-inheritance-in-javascript

2012年11月18日 星期日

KML and google map

下雨天,好憂鬱的天氣,百般無聊下,整理舊的硬碟資料,想不到看到以前的kmz檔案,想說打開軟體看一下,結果一開,掛點 orz,想說那就自己來寫吧
就拿起一本之前借來的google map書籍,想來個依樣畫葫蘆,體驗一下google map的威力,結果一查資料,才發現原來...是已經過期了,才一年多前的資料,竟然google map已經從v2搬移到v3,一堆寫法都改變了,傷腦筋!! P.S.看來這也是GPS logger附贈軟體無法運作的原因,因為api改了,這軟體應該是內嵌一個瀏覽器做map的偽裝
已經超過六七年沒寫過javascript了,好吧,接著就是開始跟ajax, jquery, google map, flot裝熟,花了兩天大致上把一些功能寫出來
  • 要能載入kml (google map搞定)
  • 要能顯示速度跟高度(要parse kml,用flot畫圖)
  • 要能依照速度資料點顯示位置(在google map上加上marker跟監控flot的onplothover事件)

基本上完成的圖案類似下面

經過一番研究,終於可以把圖表直接整合到google map上

接下來只要把kml上傳跟管理的功能整合應該就差不多,如果可以應該再來個動畫效果會更精采
直接來個demo影片吧^.^"野人獻曝了

2012年11月8日 星期四

eclipse -- plug-in directory

舊版的eclipse(<3.4)通常把plug-in直接拷貝到eclipse root directory底下的features或者plugins就可以,可是會顯得相當雜亂
在3.4之後導入了P2(Provision Platform),plug-in被安置到eclipse root directory底下的dropins目錄內了,如果是JAR只要直接放到dropins底價即可,但是如果是跟eclipse功能相關的plug-ins則是放在dropins/eclipse底下的features&plugins目錄底下

eclipse -- JRE selection

年代久了,就會有不同的java版本開發的應用程式要維護,就必須選擇相對應的JRE,eclipse可以在[window]->[preference]->[Installed JREs]裡面統一管理JRE
可以在各個專案上,按下滑鼠右鍵,然後選擇[Run as]->[Configurations]內去設定想要的JRE


eclipse -- Tasks

Tasks是指那些用註解寫在檔案內要使用的的東西,預設會使用TODO跟FIXME開頭的註解當作task,後面的註解用來描述要提示的內容,可以打開task view就可以看到需要完成的tasks
同樣的還可以自訂標籤[window]->[preference]->[java]->[compiler]->[Task Tag]
這裡要注意的是tasks跟右邊的Mylyn所主導的Task list是不一樣的,Task list比較偏向專案的工作項目,而非軟體內要注意跟改善的地方

eclipse -- SVN

安裝SVN plug-in,一樣[help]->[Install New Software],跟著選擇Collaboratin下的Subversion SVN Team Provider
安裝完畢之後重新啟動,會詢問要使用Pure Java寫成的SVN Kit或者含有windows native code的JavaHL,我選擇的是SVN Kit,接下來就是依照步驟
切換Perspective到SVN的Perspective底下,可以設定svn server相關設定
最後回到Java perspective,在某個project下按下滑鼠右鍵,選擇[team]->[share project]->svn,跟著依指示設定

eclipse -- 其他資源


  • 反組譯: JD-Eclipse
  • UML: AmaterasUML
  • SVN: VisualSVN Server
  • Tomcat : Sysdeo Tomcat
eclipse的參數可以看這裡
http://cloudtu.blogspot.tw/2007/07/eclipsememo.html
http://developer.51cto.com/art/200906/127163.htm
http://blog.163.com/fushaolin@126/blog/static/163417242201148102452497/

其實還有許多功能,比方說remote debug mode、CVS、GUI、Remote Debug、Android開發,我就不再多談了

eclipse -- JUnit

eclipse一般內建JUnit,所以很方便建立Unit Test,這裡探討JUnit 4以後,在3.0以前,都要小心翼翼的寫名稱testMethodName(),一定要寫setUp()跟tearDown(),現在全部被@Before, @After, @Test取代了
先簡單建立一個Caculator,跟著新增UnitTest檔案,介面詢問使用哪一JUnit版本,當然選4.0,在最下面填入待測試的類別
跟著eclipse很貼心的問你要測試那些方法,勾選一下就可以搞定
跟著就是把沒有的程式碼補齊
這裡看到@Before取代了setUp(),而@After取代了tearDown,@Test也是取代了test這個prefix word,所以即使不命名為testAdd()也無妨,只是我懶著更動
另外一個可以注意到的是package name,把package name跟應用程式的程式碼分開可以避免檔案混雜的問題,除非有特殊必要,不然實在沒必要把test case跟待測試的class放在一起
故意在caculator埋下了一個錯誤,在這裡就可以看到有個測試沒有通過

一般有幾種assert

  • assertEquals(expected, actual)
  • assertEuqals(expected, actual, delta)
  • assertNotNull(actual)
  • assertNull(actual)
  • assertSame(excepted,actual)
  • assertTrue(actual)

大多望文生義,第二個用於floating point計算,畢竟floating point不是連續的,如果要測試例外處理,可以使用fail() function,junit會在引發處記錄錯誤

eclipse -- 安裝web套件

最方便的應該就是直接下載含有J2EE support的eclipse,沒有的話就是自己裝囉,[help]->[install new software],跳出如下圖的介面,先選擇資料來源,eclipse有預設幾個source,先copy url,跟著按下add的時候會有詢問名稱跟url,名稱就自行填寫就可以
過一陣子,就會從網路上下載清單,有好幾個大類,找到"Web, XML, Java EE ...",然後展開,我選了底下幾個plug-in(s),另外又回頭選了幾個兩個server adapter跟web develop tools
按下下一步,他就會自行計算相依性,在按下下一步就會開始安裝,安裝完畢之後會提示重新開啟eclipse

跟著需要一個JSP/Servlet Container,當然選最一般的Tomcat 7.x,其實已經有一段時間沒有使用了,還好差不多,抓回zip檔案解壓縮,新增CATALINA_HOME(之前JAVA_HOME跟CLASSPATH已經設定過了,如果需要參考這個網址),跟著在瀏覽器打入localhost:8080,就會跳出熟悉的畫面
複習一下tomact目錄結構
  • bin Tomcat程式相關指令
  • conf Tomcat設定檔
  • lib Tomcat jar函式庫
  • logs 日誌檔
  • temp 存放暫存檔
  • webapps 網頁程式存放目錄
  • work 存放編譯好的Servlet

跟著就是建立一個新的web project,選擇dynamic web project
跟著會跳出下面的畫面,請使用者設定web container,這也就是為何在之前要安裝一些server adapter plug-in的原因,之後根據指示設定web container的環境

完成後就可以用eclipse來管理tomcat的啟動或者關閉
最後把目前的專案加入到server上去

接下來就是試著新增一個jsp file試驗看看囉,就已index.jsp為範例
比較詭異的是,他竟然不會自行publish到tomcat的目錄,必須我按下run的按鈕才可以,按下run之後會產生一個瀏覽器,要注意是,即使是更新了.jsp檔案,可能也不會即時publish,再算publish上去,也不表示會即時編譯,這可能是我設定的問題
最後可以看到右上角已經變成了Java EE


2012年11月7日 星期三

Ajax

簡單的ajax物件

var xmlHttp;
function createXMLHttpRequest(){
  if(window.ActiveXObject){
    xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  }else if (window.XMLHttpReqeust){
    xmlHttp=new XMLHttpRequest();
  }
}
基本的屬性跟方法有
abort()
getAllResponseHeaders()
getResponseHeader("header")
open("method","url", asynch, username, password)
send(content)
setRequestHeader("header","value")
<script type="text/javascript" language="javascript">
  // 修改自 AJAX: Getting Started - MDC
  function makeRequest(url) {
    var http_request = false;

    if (window.XMLHttpRequest) { // Mozilla, Safari,...
      http_request = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
      try {
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
        try {
          http_request = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {}
      }
    }

    if (!http_request) {
      alert('Giving up :( Cannot create an XMLHTTP instance');
      return false;
    }
    // 定義事件處理函數為 alterContents()
    http_request.onreadystatechange = function() { 
                                      alertContents(http_request); };
    http_request.open('GET', url, true);
    http_request.send(null);
  }

  function alertContents(http_request) {
    if (http_request.readyState == 4) {
      if (http_request.status == 200) {
        var xmldoc = http_request.responseXML;
        var nodes = xmldoc.getElementsByTagName('area');
        var mesg = "";
        for(var i=0; i<nodes.length; i  ) {
          mesg  = nodes[i].firstChild.nodeValue   "\n";
        }
        //alert(mesg);
        document.getElementById("taichung").innerHTML = mesg;
      } else {
        alert('There was a problem with the request.');
      }
    }
  }
</script>
參考資料:
  http://web.nchu.edu.tw/~jlu/classes/xml/ajax/example1.shtml

2012年11月5日 星期一

Eclipse -- java editor shortcut keys

紀錄一些有用的快捷鍵
ctrl+/ 所選的lines加上comments符號//
alt+/ 跳出補完的建議
ctrl+shift+/ 新增區塊註解/*~*/
ctrl+shift+\ 移除區塊註解/*~*/
ctrl+| 將選取的數行,全部對齊
ctrl+shift+f 格式化程式碼

format(格式化)包含了縮排的風格等等,其他還有一些快速的source code撰寫方式,真的是很方便

getter/setter是為了一些java bean或者value object設定的,不然寫起來還真累人,另外refactoring的工具就不說了,如果看懂refactoring,自然就會用,如果IDE沒有這樣的工具,我覺得refactoring執行起來的困難度真的很高

另外eclipse提供一些有關source code的提示,比方說繼承tree的展示,繼承的members的展示





Eclipse -- package explorer and the setting of jar files

package explorer一般被用來管理檔案跟packages等等設定,但是有時候太多的資訊很繁雜,有filter可以幫忙搞定這些事情
可以看到有許多可以選擇,如果只要專心於java相關檔案,不想要看到project設定的相關檔案只要把Non-java-element勾選起來,他們就會被排除掉

如果需要只專注於某一類檔案,如原始檔案(.java),只要在上面按下滑鼠右鍵,然後選擇Go-Into,那麼一來,該節點就會變成root節點了

另外一個需要設定的往往就是library,絕大多數的library其實是包裝成jar file的形式,只要在project點選滑鼠右鍵,然後選擇Properties,進入java build path選項,就可以新增jar file了







2012年11月4日 星期日

eclipse--view & perspective

打開eclispe之後,看到的樣子大概是這樣吧
整體是工作臺,而view是各種子視窗的統稱,每個view有其特殊功能,如果不小心把某個view關閉了,可以從[windows]=>[show views]=>...找回來

最近.....

其實自己最近看了一堆,寫得很少,也已經不侷限在資訊的東西了,又加上迷上evernote,幾乎所有的東西都往那邊寫了,可能會整理出來的機會就更渺茫了XD畢竟維持兩邊的同步有些困難性在

再者,有些即使是資訊的東西,也不單純屬於linux,比方說最近在翻看eclipse,或許會整理一些有關eclipse的資料。其實對很多人來說,這個已經是個很一般的工具,我也用過一陣子,大多我都在使用netbeans,對eclipse的興致來至於他廣泛的支援性,比方說php之類,也因為是java的關係,跨平台也有不錯的特性,所以不管寫android app、java/jsp、php似乎也都可以用得上,我還真的沒有好好正面碰過他

[2012/11/08]
最近eclipse的更新到了一個地步,短時間內應該不會再碰了,畢竟只是短暫的接觸,主要也是寫下一些我認為比較值得紀錄的地方,真的不適合剛剛接觸程式語言的新手,適合對程式語言與一些IDE有經驗的人

2012年10月7日 星期日

Syntax Highter for Blogger

為了塞入一些code也要有syntax highlight功能,就在網路上尋尋覓覓囉,當然很多人的blogger都有的功能,想來這是一件明顯辦得到的事情,只是找到sytaxhighlighter這個的時候,很疑惑大家都把檔案(*.js/*.css)弄到哪裡去呢?blogger是不允許上傳.js跟.css的,不會是要整個code展開到範本內吧!?後來看到人家搭配使用google協作平台,就可以把需要的檔案上傳上去,不然真的要另外找空間了

底下是簡單cpp的成果
     /**
     * SyntaxHighlighter
     */
    int foo(int counter)
    {
        if (counter <= 10)
            return;
        // it works!
    }

參考資料

2012年8月6日 星期一

影像處理基礎

試著使用mind map去做整理,看了Open CV lib感覺得好好地把數位影像處理的內容補齊,不然沒有實用的基礎,使用OpenCV只是人云亦云

2012年7月18日 星期三

Android之JNI

就如我第一篇android說的,我不是很關心android如何應用這樣的機制去寫作應用程式,但是本身卻對機制的原理相當感興趣,如果想要學會如何使用NDK做JNI可以參考參考資料,步驟大概如這張圖

針對JNI在Android上大概分成三層Java/App<=>JNI Lyaer<=>Native
因為有些動作只能在Native完成,所以不得不使用C語言,但是使用者介面又是以Java構成,要使兩者可以溝通就是透過JNI的機制
首先看Java code,必須使用System.loadLibrary載入相對應的share object(.so),對於native function則使用native關鍵字標示出來
 在java內已經宣告了java這邊的介面,用native表明到時候要透過JNI去呼叫Native程式,這時候用javah來編譯出C++ header file,使用JDK工具以特定格式去產生Native function的介面,這樣JNI才會認得兩邊的接口/介面,JNI這位中間人,就是依賴這樣的規則才能為兩邊牽線,下面是javah產生出來的.h檔案
跟著就是自行產生.cpp檔案,實作.h的介面

當呼叫System.loadLibrary的時候JNI會呼叫JNI_OnLoad函數,並且剖析share object(JNIEXPORT關鍵字做的手腳,export某些symbol),並且動態的將這些method註冊到JNI中,java code呼叫某個native method的時候其實是去尋找JNI中註冊表的method,來做呼叫

由於兩種程式語言的基本type並不相同,在兩者之間傳遞資料變成一件很重要的事情,所以如何對應呢?
<type>=>j<type>,如boolean(java)=>jboolean(c++),支援的type有boolean、byte、char、short、int、long、float、double

那麼如何在Native裡面呼叫java的某個物件的某個方法呢?其實如果熟悉Java Reflection這問題會容易解的多。
JNIEnv包含了JNI_OnLoad的時候做的資訊以及JVM的資訊,透過JNIEnv可以找到對應的class,再透過對應的class找出method與field,建構適當的signature就可執行某個object的method,跟Reflection的工作是大同小異的。


另外有個地方要注意的是,預設的狀況在Native並不會增加reference count,也就是說如果再Native functionm用static variable參考到某個object,並不表示下次來,這個object還會存在。可以使用env->NewGlobalRef(some_java_object)來取得global reference,但是要注意,這個global reference會使得garbage collect無法回收該物件,需要使用env->DeleteGlobalRef(some_java_object)來歸還


Native的exception是由JNI回報的,但是C++的異常蠻明顯不大相容於java,且處理很容易讓程式當掉,這時候JNIEnv可能用ExceptionOccured、ExceptionClear、ThrowNew報告異常

參考文件:
http://cheng-min-i-taiwan.blogspot.tw/2011/05/java-native-interface-jni-androidndk.html
http://blog.csdn.net/nicholas6lee/article/details/7324087
http://gyht0808.iteye.com/blog/763435
http://my.unix-center.net/~Simon_fu/?p=833

Learning OpenCV -- chapter 5

這一章談的是圖形的處理
blurring(平滑):用以去除雜訊或者讓影像模糊,基本原理是平均mask/filter內的pixel values
void cvSmooth(const CvArr* scr, CvArr* dst, int smoothtype=CV_GAUSSIAN,
int param1=3, int param2=0, int param3=0, int param4=0);
平滑的type有: CV_BLUR(簡單模糊)、CV_BLUR_NO_SCALE(簡單無縮放模糊)、CV_MEDIAN(中值法)、CV_GUASSIAN(高斯模糊)、CV_BILATERAL(雙邊濾波)
其中簡單與高斯支援in-place,也就是destination或取代source
對於高斯而前param1與param2分別是mask/filter的width與height,第三個參數為sigma,如果要讓xy方向不同的sigma可以使用第四個參數

形態學(Morphology)
Erode(膨脹)與Dilate(侵蝕)是兩個常見的手法,用以將影像的一個部分與kernel(核)做convolution運算,每個kernel有個anchor point(通常位於中心)。膨脹求取局部最大值,使圖形中明亮的區域擴大,侵蝕則是求取區域最小值,侵蝕可以將一些斑點的noise去除
void cvErode(IplImage *src, IplImage *des, IplConvKernel *B=NULL, int iteration=1);
void cvDilate(IplImage *src, IplImage *des, IplConvKernel *B=NULL, int iteration=1);
這兩個運算都支援in-place,若是kernel不指定,則使用3x3的kernel,iteration則表示執行的次數
建立kernel的方式為
IplConvKernel * cvCreateStructuringElementEx(int cols, inr rows, int anchor_x,int anchor_y, int shape, int* values)
望文生義,前面四個參數就不解說了,第五個參數表示形狀有CV_SHAPE_RECT、CV_SHAPE_CROSS、CV_SHAPE_ELLIPSE、CV_SHAPE_CUSTOM
第五個參數表示特定的形狀
在Morphology往往反覆使用上面兩個運算,達到一些特殊目的

void cvMorphologyEx(
   const CvArr*   src,
   CvArr*         dst,
   CvArr*         temp,
   IplConvKernel* element,
   int            operation,
   int            iterations   = 1
);
OpenCV預設支援幾種常見的operator(CV_MOP_OPEN、CV_MOP_CLOSE、CV_MOP_GRADIENT、CV_MOP_TOPHAT、CV_MOP_BLACKHAT)
Open先Dilate再Erode,去除小型的高亮度區域
Close先Erode再Dilate,去除低亮度區域的孤立點
Gradient=dilate(src)-erode(src),邊界
TopHat=src-open(src)
BlackHat=close(src)-src

Flood Fill,就如小畫家的油漆桶一般

void cvFloodFill(
   IplImage*          img,
   CvPoint            seedPoint,
   CvScalar           newVal,
   CvScalar           loDiff    = cvScalarAll(0),
   CvScalar           upDiff    = cvScalarAll(0),
   CvConnectedComp*   comp      = NULL,
   int                flags     = 4,
   CvArr*             mask      = NULL
);

調整大小

void cvResize(
   const CvArr*   src,
   CvArr*         dst,
   int            interpolation = CV_INTER_LINEAR
);
其中調整的時候是如何處理過多或者刪減的pixels,由最後一個參數指定,有CV_INTER_NN (Nearest neighbor)、CV_INTER_LINEAR(Bilinear)、CV_INTER_AREA(Pixel area re-sampling)、CV_INTER_CUBIC(Bicubic interpolation)


Image Pyramids看不懂,orz


Threshold,運算有

double cvThreshold(
   CvArr*         src,
   CvArr*         dst,
   double         threshold,
   double         max_value,
   int            threshold_type
);


相對應的type為CV_THRESH_BINARY、CV_THRESH_BINARY_INV、CV_THRESH_TRUNC
CV_THRESH_TOZERO_INV、CV_THRESH_TOZERO


取threshold是一種技巧,友人發展出自動化的技巧,透過加權平均的方式自行取得threshold

void cvAdaptiveThreshold(
   CvArr*         src,
   CvArr*         dst,
   double         max_val,
   int            adaptive_method = CV_ADAPTIVE_THRESH_MEAN_C
   int            threshold_type  = CV_THRESH_BINARY,
   int            block_size      = 3,
   double         param1          = 5
);
這個function並不支援in-place

以上的函數都是OpenCV已經幫忙實作完畢,只要直接套用就可以,相當方便,但是重點應該是何時該使用何種運算,以及運算背後代表的意義,才是我們要學習的重點(還是直接去翻閱Digital Image Processing的書XD)



2012年7月17日 星期二

android架構

在Android架構,總共是由5個部份來組成。分別是:
(1)Applications(應用程式)
(2)Application Framework(應用程式架構)
(3)Libraries(函式庫)
(4)Android Runtime(Android執行環境)
(5)Linux Kernel(Linux核心)
大多數的網路資訊引用了類似這樣的圖形
我注意到比較有趣的是Binder (IPC) driver被嵌入了kernel,印象中這是android創建的IPC機制。許多人也知道android上的app開發大多是java,也就是java透過application framework在與底層的JNI以及Native的library做溝通,而我感興趣的就是底層的部分(application framework以下)
為何會對這部分有興致,主要想要操作camera以及最近遇到一個有人release出來的ICS版本,但是SD卡卻無法順利掛載,開始追蹤Vold這個deamon(android藉由uevent實作出來的一個動態掛載volumn的機制),或許就是為了喝牛奶養了一條牛吧XD
最後補上一個camera個架構圖
參考資料:
http://my.opera.com/ozzyyngwie/blog/android-an-open-mobile-platform
http://www.kandroid.org/online-pdk/guide/camera.html

Learning OpenCV -- chapter 3之一

OpenCV的主要四種基本資料結構
CvPoint => CvPoint2D32f, CvPoint3D32f,最前面為兩個整數變數x,y 後者則為浮點數
CvSize => CvSize2D32f,兩個整數變數width, height或者為浮點數的結構
CvRect有成員x, y, width, height
CvScalar,四個double的數值,再不考量記憶體使用量可以用來取代前面三者
通常constructor為cvPoint()或者cvSize,也就是第一個字母為小寫的function,在這裡雖然OpenCV是用c語言寫成,但是其實有不少物件的觀念,所以就借用了constructor一詞,但是並非真的是constructor

圖形的資料結構
CvArr
CvMat
IplImage
如果有個function要求CvArray*,則可以放入CvMat*或者IplImage*,同理要求CvMat*則可放入IplImage*,可以將關係視為繼承,也就是說is-a的關係



CvMat * cvCreateMat(int rows,int cols, int type);
表示這為一個二維陣列,望文生義,rows跟cols表示列跟行,type則是
CV_<bit_depth>(S|U|F)C<number_of_channels>
bit_depth也就是色階,S|U|F表示signed|unsigned|floating-point,C表示channel個數
CV8UC3,表示每個pixels由3個channel構成,每個channel用8bits表示
data則是實際儲存資料的地方
而cvCreateMat實際上呼叫了cvCreateMatHeader()與cvCreateMatData(),前者填充rows/cols/type等等,後者對儲存資料的空間作配置,所以如果不需配置記憶體的時候,或者共享某個區塊的時候,就只要呼叫cvCreateMatHeader就可以了。如果是複製某個區塊,使用cvCloneMat(CvMat*),有配置就必要釋放cvReleaseMat(CvMat*)

存取CvMat資料的方式有用Macro
CvMat *mat=cvCreateMat(5,5,CV_32FC1);
CV_MAT_ELE(*mat,float,3,2);
*((float*)CV_MAT_ELE_PRT(*mat,float,3,2))=5.5
由參數得知,必須要知道data的type才能計算到正確位置,還有就是它是一次性計算,也就是非指標運算,對於連續存取很沒效率

另外一種為cvPtr*D與cvGet*D的方式取得指標,用於各種維度
uchar* cvPtr1D(const CvArr* arr, int idx0, int *type=NULL)
uchar* cvPtr2D(const CvArr* arr, int idx0, int idx1, int *type=NULL)
uchar* cvPtr3D(const CvArr* arr, int idx0, int idx1, int idx2, int *type=NULL)
uchar* cvPtrND(const CvArr* arr, int *idx, int *type=NULL, int create_node=1, unsigned* precalc_hashval=NULL)
或者
double cvGetReal1D(const CvArra *arr, int idx0)
double cvGetReal2D(const CvArra *arr, int idx0, int idx1)
double cvGetReal3D(const CvArra *arr, int idx0, int idx1, int idx2)
double cvGetRealND(const CvArra *arr, int *idx)

CvScalar cvGet1D(const CvArr *arr, int idx0)
CvScalar cvGet2D(const CvArr *arr, int idx0, int idx1)
CvScalar cvGet3D(const CvArr *arr, int idx0, int idx1, int idx2)
CvScalar cvGetND(const CvArr *arr, int *idx)

其中cvPtr*D取得為每個pixel,如果有3個channel,則為rgbrgbrgb...等地排列方式,這部分區自行處理,好處是可以快速地訪問,另外有cvGet*D就有cvSet*D
另外要注意的是CvMat未必是連續空間,最多保證每個row是連續的

從上面可以看到IplImage的成員,大多可以望文生義
重要的有origin,表示原點座標是放置在IPL_ORIGIN_TL左上角(一般電腦圖形)或者IPL_ORIGIN_BL左下角(一般數學座標)
dataOrder表示資料是每個IPL_DATA_ORDER_PIXEL或者IPL_DATA_ORDER_PLANE,前者表示rgbrgbrg這樣的資料排列,後者表示rrrrr...ggggg...bbbbb....這樣三面的排列,所以儲存影像資料的imageData就受到這個參數的影響,必須知道資料正確的排列才能正確處理資料
ROI則是感興趣的範圍,用以將圖形特定範圍切出,用來處理這部分,有mask的觀念,可以使用
void cvSetImageROI(IplImage *img, CvRect rect)
void cvResetImageROI(IplImge *img)
可見一個IplImage只能設定一個ROI,但是要保留多個ROI,書中有範例技巧
參考資料:
http://yester-place.blogspot.tw/2008/07/cvmat.html
http://yester-place.blogspot.tw/2008/07/iplimage1.html

2012年7月16日 星期一

Learning OpenCV -- chapter 2

載入image到記憶體
IplImage *img=cvLoadImage(filepath);
載入avi檔案,並且使用cvQueryFrame取得下一個frame
CvCapture *capture=cvCreateFileCapture(path);
IplImage *frame;
for(...){ frame=cvQueryFrame(caputre);}
調整capture,cvSetCapturePropertycvGetCaputreProperty
cvSetCaptureProperty(caputre,CV_CAP_PROP_POS_FRAME,pos);
建立影像,第一個參數為大小,第二個為每個channel的bits數,第三個為通道數目
IplImage *out=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
使用演算法
cvSmooth(img,out,CV_GAUSSIAN,3,3);
建立一半大小的影像
IplImage *out=cvCreateImage(cvSize(img->width/2,img->height/2),img->depth,img->nChannel);
cvPyrDown(img,out);
從上面可以知道,所有重要的資料都被封裝成struct,然後以指標的形式在傳遞

總結以上,OpenCV是一個C lib的library,提供一個快速開發的介面,有效的節省programmer的時間,我想主要的目的是驗證一些演算法吧,真的還蠻方便的

2012年7月15日 星期日

OpenCV 2.4與Visual C++ 2010 Express

主要參考這裡
http://www.cnblogs.com/freedomshe/archive/2012/04/25/2470540.html

大致上就是設定include、設定lib,還要設定linker lib,最後記得把環境變數加進來,讓程式找的到dll,之前裝VC 2008 Express因為忘記設定(其實是找不到orz,好個VS,設定改來改去),結果就一堆symbol找不到的問題

2012年7月14日 星期六

udev的流程

udev主要功能

  • 允許動態建立刪除裝置
  • 自行配置裝置編號
  • 根據規則建立名稱,而非固定名稱
  • 建立kobject物件


udev其實利用了kobject在/sys下面建立的動態的系統資訊,udev主要成分,namedev、libsys、udev

udev配合hotplug機制,每當有裝置加入的時候,建立sysfs(kobject)下的相對應節點,跟著呼叫namedev在/dev下建立相對應的裝置
如果理解bus、device與driver三者的關係,可以理解到udev功能是可以達成的,但是接著升起的疑問是,流程是如何呢?

bus會利用match這個操作方式尋找合適的device以及driver,但是因為需要kobject來在sysfs下建立相對應的結構,是否意味著要改寫driver?從參考資料的解說,應該是不必。udev會監控linux載入的module,自動生成kobject

所以一開始就註冊了bus,udev會在module載入的時候紀錄準備生成kobject,當裝置插入主機的時候,跟著建立device,使用bus尋找到相關driver,最後udev會生成kobject,也就是在/sys下建立相對應的目錄

bus(開機時候)=>driver/udev(載入module時候)=>device(裝置插入主機接上某個bus)=>/dev/xxx與/sys/bus/xxx建立(udev透過bus.match建立)

以上就是我的理解,不知道有沒有錯誤

參考資料:
http://daydreamer.idv.tw/rewrite.php/read-49.html

2012年7月4日 星期三

character driver的岔路上

不能免俗,絕大多數入門的linux driver,除了第一個hello world module之外,跟的就是character driver,因為他最貼近一般人使用fopen, fread, fwrite, fclose的直覺
推薦服用宋寶華的範例,但是在2ed chapter 6使用的測試指令為
echo "hello world"> /dev/globalmem
cat /dev/globalmem
以上可以正常運作,可是跟著我就開始試著其他組合
echo "hello world"> /dev/globalmem
echo "again"> /dev/globalmem
cat /dev/globalmem
開始似乎不大正常的運作,即使使用
echo "hello world"> /dev/globalmem
echo "again">> /dev/globalmem
cat /dev/globalmem
也於事無補,我開始懷疑ppos這個表示目前檔案位置的參數有沒以正確運作,在經過一番追蹤,似乎發現不如預期。我恍然大悟,原來要從process、file、inode角度去切入,就明白這一切了。


過程中我也寫了個簡單的程式,使用fopen, fread, fwrite, fclose去操作,因為一點點小小的失誤反而讓我看到一些覺得奇怪的地方,首先fopen, fread, fwrite, fclose的應該是對應到了driver內的operations,但是我在fopen的時候,最後讀寫模式寫錯了"w+",只寫了"w",結果編譯過程還是通過了,但是fread沒有作用,照樣有輸出,真是好神奇阿@@a有興趣的人可以用strace試驗看看

cross compile strace

指令如下
CC=arm-linux-gcc LD=arm-linux-ld RANLIB=arm-linux-ranlib ./configure --host=arm-linux --target=arm-linux --prefix=./install_dir
完成之後直接放到Target上就可以了
相關資料
https://www.ibm.com/developerworks/cn/linux/l-tsl/

ioremap的理由

參考資料內說得非常好,有許多理由
1. 一般io access, 有所謂的IO bus或使用memory mapped IO, 以I386而言,   它有in/out系列的instruction來做IO bus access, 而ARM則沒有. 
2. 對於IO bus access, 一般driver只要有access right就可, 而由於一般而   言C/C++ 無法generate in/out系列的instruction, 所以要以inline   assembly來達成這個目的, 而一般的inb(), inw(), outb(), outw()...等   等的functions或macros會可以做到這件事. 
3. 對於memory mapped IO, 由於是直接access memory, 必須跟OS的memory   system結合, 所以就會有一些access right, non-cacheable, virtual   address等的問題. 
4. 對PCI而言, 還有所謂的PCI bus address, 而一般PCI bus driver在啟動   後會enumerate上面的card, 了解它們的memory regions的size, 並assign   PCI bus address給每一memory region, 至於如何由system bus address   對到PCI bus address要看SOC的設計. 在access時, 是virtual address->   physical address->PCI bus address. 
5. OS並不會知道那一塊被拿來當memory mapped IO, 所以, 往往是只有開放   RAM的部份的space, 其實一般startup code其MMU的部份還會打開SOC的   register space或一些local bus banks的space, 以相同的virtual address   來使用對應的physical address, 但是, startup code一般我們希望不要   放太多變動性太大的東西, 這樣也會把太多枝枝葉葉的codes放入主要程式   中, 另外, 與PCI相關的考量放入startup code, 也會變得很繁瑣. 所以   ioremap很重要的是就是讓driver可以為它要使用的空間找到一塊virtual   address的space. 
6. 有一些扁平式的設計, 直接一開始全部對應好, 將4G virtual address對應   到等值的physical address, 所以你不用ioremap也可使用正常, 不過, 使   用ioremap也沒甚麼不好吧, 反而是養成良好的習慣. 而通常, 有virtual   memory的MMU, 一般都是只開有限的區域, 即使它們只是直接對應等值的   address, 因為這樣可以加強系統的debug功能, report非法的memory access. 
7. 一般ARM有分TLB或protection unit的, protection unit只做保護和cache/   write buffer的控制, TLB則可以實現virtual memory.

因為一般在kernel模式下操作的是virtual address,透過MMU的page table來處理virtual address與physical address,但是實體io port或者memory,要是直接存取會產生兩個問題,一個是受限於特殊硬體架構,另外一個是不應直接處理physical address。於是乎ioremap就是透過修改page table,讓physical address對應到virtual address(等於在virtual address規劃出一區塊,使OS知道使用該區塊等同在使用某區塊的physical address),這樣一來就某種程度隔開特殊的硬體架構,也避免直接使用physical address。

跟著由於硬體的特性,雖然ioreamp讓程式設計師使用實體記憶體如同使用一般memory一樣,但是因為有時硬體可能只是個io port,訊號隨著時間一直變動(有點類似volatile變數一樣),所以在讀取跟寫入的時候最好透過特殊函數如writel或者readl之類,不要直接用assign operator(等號)

http://www.programmer-club.com/showSameTitleN/embedded/1820.html
http://blog.csdn.net/do2jiang/article/details/5450839

2012年7月1日 星期日

inode、file以及container_of

回顧LDD3的第一個character device範例,其實感覺裡面一次給出了太多東西,會令人暈頭轉向,其實在宋寶華的書中給出一個比較簡單的範例


  • LDD3一次配置多個device,對多個device視為同一類,使用同一個module
  • 宋寶華一開始只有一個device,只給定一個module


兩者之間的差異決定的對程式展現的方式,其中以container_of這個macro最為經典,建議先看完宋寶華的範例,再瀏覽LDD3的範例,可以知道這個macro的關鍵性作用


LDD3展示了,一個module可以同時為同一類的裝置提供驅動程式,讓device(裝置)與operations(操作),可以結合,同時可以分開,一個module提供多個裝置,相同的操作,其中隱含了物件或者說ADT(abstract data type)的概念,這個在driver開方上很重要,udev更是把這種概念發揚光大

inode跟file兩個重要的結構提供了不同的作用,inode大多存在於kernel space,file則是user/kernel space都有(使用者一般操作file),同時也是支撐VFS (virtual file system)的兩個重要結構


  • file結構有兩個重要成員,一個是file_operations,也就是操作file的functions,另外一個是private_data指標,通常module會將對應的device資料的記憶體位置交給private_data
  • inode則擁有i_cdev或者i_bdev,分別表示character device或者block device這兩個指標,雖然一般開發者會重新包裝自己的結構,將struct cdev包裝起來,以支援定義的驅動程式,如LDD3範例


struct scull_dev {
struct scull_qset *data;  /* Pointer to first quantum set */
int quantum;              /* the current quantum size */
int qset;                 /* the current array size */
unsigned long size;       /* amount of data stored here */
unsigned int access_key;  /* used by sculluid and scullpriv */
struct semaphore sem;     /* mutual exclusion semaphore     */
struct cdev cdev;  /* Char device structure */
};

struct scull_dev *scull_devices; /* allocated in scull_init_module */
最後一個scull_devices表示一堆同類的devices

有了以上的瞭解之後來看open、read函數
static int open(struct inode *inode,struct file *filp){
...
}


static ssize_t read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){
...
}

在LDD3的範例在init函數配置好了所有的scull dev(因為不只一個device),但是在open函數的時候要如何找到對應的scull_devices中的哪一個?因為我們想把他assign給file.private_data方便以後給read函數使用
一般而言,由於inode包含了cdev這個變數,我們知道cdev來自於scull_dev裡面,所以會想藉此找出scull_dev,裡面包含了如何計算cdev應該在scull_dev內的位移,配合位移,藉由調整記憶體的address,我們就可以找到scull_dev了,而此時container_of就可以幫我們忙

struct scull_dev *dev; /* device information */


dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
constainer_of這個macro會自動完成計算位移以及轉型的動作,將目前打開的device所指向的scull_dev變數找出來。也就是只有scull_device.cdev結構成員,卻可以找到scull_dev的結構變數。做了那麼多工作,就是為了把scull_device配置給filp->private_data,後面read函數就可以應用她了

如果今天只有一個device,那麼其實也不用那麼麻煩,就如宋寶華的範例,直接將struct scull_dev onlyone設定為global變數,然後直接在open函數的時候assign給filp->private_data即可


由上面可以了解到,LDD3在一個範例內展示了

  • VFS這樣的抽象操作需要file以及inode配合
  • scull這個module可以同時支援多個一樣的裝置
  • 如何註冊character device,以及要注意的事項
  • 如何實作file operations
  • 隱含在Linux Device Driver中分層以及分工的架構
  • ...

不細看還真的很難體驗這個module竟然有如此多的東西,也感嘆這章節竟然寫得如是簡單/簡潔,真的不知道LDD3的作者是故意的還是假設讀者的Linux背景很夠

如果有興趣了解container_of到底如何運作,可以參考參考資料連結

參考資料:
http://space.itpub.net/14805538/viewspace-445624
http://tw.myblog.yahoo.com/hughes-blog/article?mid=88&prev=-1&next=87

2012年6月30日 星期六

Hello World Module

不能免俗的一個hello world等級的module,基本上就是學習編譯技巧跟觀察,一點作用都沒有
檔案為hello.c位於某個版本的kernel source下的drivers/hello目錄內,比如說/home/account/friendarm/kernel/linux-2.6.32.2/hello,底下有兩個檔案hello.c跟Makefile
Makefile只有兩行,一行指定compiler,另外一行就是module的相依行囉
編譯指令為
make -C /home/account/friendarm/kernel/linux-2.6.32.2 M='drivers/hello' modules
-C後面的參數為kernel source tree位置,後面則是要編譯的module的位置

我跟著是放到micro2440上面執行(如果在桌上型,Makefile內的CC可以省略,直接用系統內建就可以了),因為micro2440上面預設把所有訊息打開了,所以可以在console底下看到訊息輸出,不然一般應該在/var/log/messages檔案內

2012年6月28日 星期四

linux input subsystem

linux input的subsystem已經發展許久,為了簡化driver,系統發展出了input core的部分,不過也是因為這樣,使用者在使用方便之餘,已經搞不清楚到底事件的觸發是如何從source to destination了,還好linux是開放原始碼,所以trace source code還是可以瞧出端倪的

很多書本不知道是為了哪種理由,其實這部分大多很含糊的略過,只簡單提到使用input_register_device()去註冊由input_allocate_device()配置出來的device,然後跟著使用input_event()跟input_sync()完成工作,最多再給出個虛擬的滑鼠的範例,結束

看完之後我還是搞不懂,事件如何導向消化的地方,我可否自行寫一個輸入系統,再自行寫一個handler來處理呢?直覺上是可行的,但是如果不了解如何運作,恐怕也是很難做到

透過drivers/input/input.c的source code解析可以得到答案,不過網路上已經有人剖析得很清楚,我就直接借用連結過來吧
http://blog.163.com/wxiongn@126/blog/static/1178820382010724104617786/
http://blog.163.com/wxiongn@126/blog/static/117882038201072410502312/

2012年6月16日 星期六

個人認為的linux驅動程式學習步驟

linux驅動程式開發的門檻比一般程式設計的門檻高,原因在於對於硬體及韌體的了解需要比一般的更多,相較之下,如web service的開發則傾向設計的門檻比較高,比方說MVC的應用,以及類似DB的設計等等,幾乎是不同的走向

linux驅動程式開發最好對硬體有些了解(本人對硬體就很不了解,花了不少時間填補),再者對於一些作業系統的基本元件,如process、semaphore...等等要有概念,接著了解system programming(指那些system call),跟著可以開始作驅動程式開發

  • 如果是嵌入式系統,可以overview各種cpu、chip、memory、hardware interfaces開始;跟著必須補齊如boot loader、kernel、root system等等概念,oreilly的"建構嵌入式linux系統"是本這方面的好書,相對的PC上的linux就比較沒有這方面的疑問,很多都已經非常的標準化了,變化行不如嵌入式系統大
  • 基本的裝置分類方式character、block、queue,學習linux從高階的角度看待各種設備。
  • 驅動程式IO的元素,如blocking/non-blocking、synchronous/asynchronous、critical section的維護、device/device_memory IO、記憶體的操作(kmalloc、__get_free_page...)、interrupt。因為驅動程式主要就是為了輸入、輸出訊號,這些元素都是必備的
  • 接著了解bus/device/driver的架構、分層(layer)、分離、子系統(input、usb...)的應用。這部份有些書本略過了,真的很難消化,網路上資源不少,但是又很少願意以圖形說明,如果只有自己爬code會很累
  • 在貼近各種bus界面,以及硬體的控制,如PCI、USB、I2C...
  • 其他還有debug的技巧

整體linux的學習過程應該要花上好些時間,再者如果每個部份又不是很熟悉又很容易因為一同栽入,見樹不見林,我想提供一個簡單的方向讓有心的人可以稍微有點概念。
我認為最難的兩個部份,一個是linux driver的架構、各種子系統的設計,其實因為發展了許久,所以開始結構化,但是結構化就是簡化程式碼,但是提昇程式碼之間的相關性,再不了解相關性(如子系統的原理),看code就倍感吃力;其次是各種硬體跟界面的經驗,跟界面也都有他的設計的經驗跟原則,當使用者或者一般程式設計師都有OS幫忙處理,所以現在要寫這一層,就比較吃力一點。最後,當然最好的是身邊有個熟悉的人,可以讓你一直問:P但是這真的是看緣份了

最後應該就是硬體的資訊,這方面不屬於韌體工程是的範疇,但是又有點難分割,在業界有vendor廠商提供主要的幫忙,但是了解愈多愈能幫助自己完成工作

最後我想說,相較於四、五年前現在資料真的多許多,主要是拜android風行之賜,相關資料一下子有了爆炸行的成長

2012年6月15日 星期五

linux驅動程式-chapter 7

這個章節看似比較鬆散一點,不過如果從了解中斷的角度應該會比較容易入手一點
先想想中斷,中斷分類可以分成幾種

  • 從來源,分為內部中斷(cpu引起,如除0)跟外部中斷(硬體週邊引起)
  • 從是否可遮罩,分成可遮罩與不可遮罩
  • 從中斷處理函數,分成向量中斷跟非向量中斷

不論如何,基本的處理精神都是希望趕緊將中斷處理完畢跟著把控制權交還給本來的程式,很可惜有的中斷要長時間處理,比方鏡頭要拷貝整個影像,這需要長時間
所以很多OS設計就將中斷分成兩個部份,一個部份是處理引發的事情,讀入一些需要的資料(如暫存器),記憶體拷貝的部份在另外找時間處理,以如此折衷的方式進行。前面稱為中斷的top half,後續的處理過程稱為bottom half。

跟著我們知道有個獨特的中斷為計時中斷,很多軟體的timer也是基於此設計,書中先介紹不使用OS支援的方式實作timer,跟著引入有OS支援的方式

一開始介紹了如何使用jiffies來計算時間,每個jiffiers是一次震盪的時間(不管是cpu或者是主機板上的石英振盪器),一開始書本給的範例是使用busy waiting的方式來計時,也就是讓程式一直消耗cpu,且反覆觀察jiffies的變化,透過time_after、time_before等函數來比較jiffies變數之間的大小,進而達成timer的作法
很明顯busy waiting的方式當然是不好的,與其等待不如把cpu讓給有需要的人。另外就是OS為了服務更多的timer(想像很多process需要定時執行某些事情,這些process需要很多timers),於是OS維護了一個timers的list,每隔一段時間就檢驗這些list,並且將那些時間到了的process放入排程(schedule)之中
而這樣的作法就是將那些process視為half bottom,而kernel中檢驗list中的timer變成了half top,中斷發生的時候就快速篩選timer並且進入排程
一個簡化的版本是呼叫schedule_timeout()該函數中是使用timer_list來維護

接著談到中斷的bottom half的實作方式有tasklet與work queue的方式

2012年6月14日 星期四

Linux之AIO

雖然這已經是很久之前就存在的技術,但是感覺在一般的程式設計書籍並不常見(應該說比例上),但是最近AIO卻是延伸到web server上變得火紅,從node.js可見一斑
主要是因為閱讀蒐集linux driver的資料的時候看到的,因為感覺LDD這本書有點看不懂,可能礙於實際開發經驗,以及程式設計背景知識,即使知道了如何寫出driver,但是感覺並無法實際充分利用。所以我也另外買了一本大陸作者的書籍"Linux 裝置驅動程式之開發詳解(第2版)",前面講解還算通暢,可是到了AIO左右已經開始有點不知所云,轉而向網路搜尋,找到了M. Tim Jones的著作,他並非亞洲人
http://www.ibm.com/developerworks/cn/linux/l-async/
發現原來該書的作者應該是瞟竊他人的著作!!??雖然後來唸到後面有看到一個URL指向該文章,也不知道這個網路文章(已經翻譯成中文)是否為書本作者翻譯的,但是完全不加以註明,讓人覺得書本文章是他自己寫的,書中一段文字幾乎跟網頁文字相同!!再加上範例也很像。
我發現難以理解主要是因為書本作者根本把一些重要的網頁圖片拿掉,如下面的圖片,明白點出blocking/nonblocking跟asynchronous/synchronous之間衍生的關係


建議對書中看得不大懂的讀者,轉向直接閱讀該網頁的內容,其中還有四個圖案講解kernel跟這四種IO之間的關係,簡明易懂,個人看了感覺大有收穫

2012年5月16日 星期三

Linux驅動程式--chapter 13

這一章節主要介紹USB,這也是linux中相當複雜的一部份,書中感覺也是概略性介紹,我在網路上爬了一些資源,先記錄下來,再回頭來寫摘要

相關資源:
http://www.ibm.com/developerworks/cn/linux/l-usb/index1.html
http://www.ibm.com/developerworks/cn/linux/l-usb/index2.html
http://blog.csdn.net/fudan_abc/article/details/6820580
http://kezeodsnx.pixnet.net/blog/post/27794098-%5B%E8%BD%89%E8%B2%BC%5D-linux-%E4%BD%BF%E7%94%A8-usb-%E8%A3%9D%E7%BD%AE%E7%AD%86%E8%A8%98-
http://linux.chinaitlab.com/driver/877123.html
http://lwn.net/Articles/143397/

Linux驅動程式

已經好久沒更新了:P,因為最近都忙著補充以前"流失"的硬體相關資訊,書本囫圇吞棗的已經看到chapter 13去了,但是都沒整理。發現這linux driver真的是個大課題,然而這本書很可惜無法面面俱到(如果要寫的詳細,我想上千頁應該是基本的吧),書本優點是已經將大多需要用到的原則以及重要的原件都提到,可是底下是不足的地方

  • 後面章節的範例愈來愈缺乏實作性質。也就是大多屬於simple code的範疇,並無法很順利地跟實際開發相連
  • 與硬體連接的部分沒有更多的敘述。我想這點應該是取捨的問題,不大算是不足,不過如果需要硬體底層的資訊,可能還要在網路或者其他書籍中尋找
  • 與kernel相關的部分著墨不過多。driver往往與kernel相關,書中並沒有比較詳細的闡明兩者之間的關係,或許是作者想要在抽象層面做介紹,如果與kernel連結,又不綁定特定平台,恐怕書本真的太厚
  • 後面章節流於形式介紹。可能作者對於驅動程式開發太熟悉,內容看起來都很類似steps 1, 2, ...,並每有很生動的場景(scenario),對於理解幫助有限

我想把這本書看完之後,應該會在去找上一兩本linux driver的書籍來看吧,另外開始研究linux核心到底做了甚麼事,當然同時不可避免地必須了解硬體的一些相關資訊

2012年4月22日 星期日

static function in C

 static functions are functions that are only visable to other functions in the same file.  
也就是說static function在C語言內並不跟static variable的語意一致,static在java上面是一致的
C語言static function的控制是visability,但是在static variable則是life time

2012年4月21日 星期六

一些kernel的process/thread

ps -ef可以看到一堆kernel啟動的程式是使用[中括弧]括弧起來的,底下是我知到的有
ksoftirqd/0:軟體中斷的daemon,後面的號碼表示thread個數,比方說2cores 4threads
kworker:APIC的wait queue
kthreadd:kernel thread的parent daemon
kswapd0:swap daemon
migration:將process由某個core移動到另外一個core
其中有些process在ubuntu上面找不到
pdflush:將一些dirty pages作輸出
events/n:working queue

其實在過程中有看到kernel thread,我很好奇kernel thread在概念上跟thread有何差異?對於kernel thread跟process的對應關係又是如何也感到很好奇

參考資料
http://hi.baidu.com/nixsql/blog/item/c8f042ef2018863127979116.html
http://ubuntuforums.org/showthread.php?t=1630347

2012年4月18日 星期三

Cloud Projector

最近都在弄硬體的東西,反倒是忽略了這個blog,先放一兩張之前用BeagleBoard做的projector,理想上就是利用BB加連上投影機,然後用瀏覽器,比如說平板上面的瀏覽器來作遠端遙控,至於投影片是放在網際網路上面的
螢幕試用台代替投影機,可以看到BB只有外加上一個USB無線網卡,本來電源是想要用電池的,可惜市面上買到的電池組裝起來電流不夠穩定,所以電源還是接到變壓器,改天有空自己再來作一個。可以看到平板上面會顯示跟投影機上面一樣的縮圖

可以看到上面細項的參數,主要就是一個URL跟一個頁數還有目前頁數的顯示以及一些簡單的跳頁、上一頁、下一頁

目前可以轉換網頁跟pdf檔案,以後應該開始考慮轉換google的投影片,一樣有空在研究吧