2007년 9월 3일 월요일

Setting up a CVS repository - the pragmatic way

소 잃고 외양간 고친다는 속담이 이 경우에 딱 들어맞는 경우인것 같습니다. cvs repository로 사용하는 linux(WowLinux Paran2)의 filesystem이 완전히 엉망이 되어서(fsck 명령어를 잘못 수행하는 바람에 -_-) 복구 불능이 되어버렸습니다. 복구해도 lost+found 디렉토리에 숫자로된 엄청난 양의 파일들만 뱉어내는 바람에 한숨을 쉬고 나니 지난 2년동안 모아 둔 저장소가 복구가 불가능 한 것을 알고 포기했습니다. 실은 VMWare로 동작하는 거라서 5개월 전 즈음해서 snapshot을 받은 것이 있어서 5개월 전으로 linux 전체 시스템을 복구하는 것은 가능했지만 문제는 CVS 를 백업해
두지 못해서 복구를 할수가 없었습니다. 불행중 다행인 것은 작업하기 전에 CVS를 모두 Checkout 을 해둔 터라 최종 소스는 모두 가지고 있었지만... 솔직히 나 자신이 멍청하다고 생각한 것이 checkout을 한 것을 가지고 CVS 저장소를 복구할 수 있을거란 생각을 여태 가지고 있었다는 사실이었습니다.

CVS is not backup tool!

마지 GNU is not UNIX! 란 슬로건이 생각이 나네요. 어찌되었든 CVS는 자체적인 백업툴을 가지고 있지않습니다. subversion은 이러한 CVS의 단점을 보완해서 백업툴과 같은 것을 가지고 있어서 이번에 다시 저장소를 꾸밀때 svn을 쓸까 cvs를 쓸까 주말내내 두가지 툴을 비교해보았는데 결론은 cvs를 쓰기로 했습니다. 이유는

1. file 단위로 비교하는 version control에 익숙해서
2. webcvs, cvsgraph 가 없으면 허전해서(svn은 websvn을 사용합니다.)
3. svn 사용법을 다른 사람에게 가르쳐주기 귀찮아서
4. svn 설치하기 귀찮아서

그런데 그냥 예전처럼 CVS를 사용하면 외양간 고치는 것 치고는 너무 부실한 것으로 보여서 약간은 BSD style 스럽게 사용해 보고자 하고 꾸며 보았습니다. webcvs가 없는 cvs는 상상도 하기 싫어하기 때문에 bsd 웹 사이트를 보면서 아마 이렇게 꾸미지 않았을까 상상하면서 저장소를 예쁘게(?) 꾸며봤습니다.

-. cvsweb.freebsd.org
-. cvsweb.netbsd.org

그리고 이번 기회에 cvs 저장소는 NetBSD 환경으로 완전히 이전해 버릴 작정입니다. 워낙 기존에 사용하던 linux를 관리하지 않아서 너무 난잡해져 ugly한 모습으로 변해 버려서 이 녀석은 Oracle DB 서버로만 그 기능을 할수 있게끔 할 계획입니다.


NetBSD 설치
-----------
현재 stable 버전인 3.1로 설치했습니다. 모두 선택해서 설치해도 300MB가 조금 넘는 컴팩트한 사이즈로 설치되고 X system도 사용이 가능하니 설치 만큼은 NetBSD가 현 UNIX계열중에는 최고인 것 같습니다. 추가로 설치는 사실상 VMWare로 설치를 한 것이라 설치 끝나고 snapshot 한번 해놓으면 끝.


CVS repository 설정
-------------------
1. cvs 관리 계정 생성
# groupadd -g 2401 cvs
# useradd -s /bin/csh -d /home/cvs -m -g cvs -u 2401 cvs

NOTE. pserver 서비스 포트가 2401이다 보니 전 이렇게 구성을 했습니다. 개인적으로 csh을 좋아하는 편이라 cvs 관리 계정은 이렇게 생성합니다.

2. 카테고리별 저장소 생성
# mkdir /var/cvs
# chown -R cvs:cvs /var/cvs
# chmod ug+rwx /var/cvs
# su - cvs
% cd /var/cvs
% mkdir ${projectcategory}-cvsroot
% chmod ug+rwx ${projectcategory}-cvsroot
% cd ${projectcategory}-cvsroot
% cvs -d /var/cvs/${projectcategory}-cvsroot init
(/var/cvs/${projectcategory}-cvsroot/CVSROOT가 생성됨)

USAGE. ${projectcategory} 는 원하는 프로젝트 카테고리 이름

NOTE. 전에는 가장 일반적인 다음 방법을 사용했었습니다.

# su - cvs
% cvs -d /home/cvs init
(/home/cvs/CVSROOT가 생성됨)

그런 다음 /home/cvs 밑에 모든 프로젝트가 위치하는 식으로 관리를 했었는데 쓰다보니 몇가지 불편한 점이 있었습니다. 가장 큰 사항은 접근 관리(access control)였는데 사내의 다른 인원(trusted user)에게는 저장소에 유저를 추가하는 방법으로 사용해도 큰 문제는 없었는데 저장소에 외부 인원(untrusted user)에게 공개할 때가 가장 짜증나면서도 번거롭기 그지 없었습니다. 저장소를 하나만 쓰다보니 write권한을 주면 해당 프로젝트 뿐 아니라 다른 프로젝트에 까지 write권한이 주어져서 아주 골치가 아프더군요. 제가 알기로 처음에는 cvs 저장소에 어떤 프로젝트 리스트가 있는지 알기가 상당히 어려워졌는데 요즘은 명령어 하나로 프로젝트 리스트를 얻어오는 방법이 있습니다. 어찌되었는 접근 관리로 인해서 프로젝트별로 저장소를 별개로 가져가는 것이 가장 좋은 방법으로 보이고 실제로 BSD 계열의 CVS를 보아도 현재 그렇게 사용하고 있습니다.
가장 단적으로 보여줄수 있는 것은 FreeBSD진영의 cvsweb.freebsd.org로 web으로 보면 다음처럼 꾸며져 있는 것을 알수 있습니다.

cvsweb.freebsd.org
-. CVSROOT/
-. CVSROOT-doc/
-. CVSROOT-ports/
-. CVSROOT-projects/
-. CVSROOT-src/
-. distrib/
-. doc/
-. ports/
-. projects/
-. src/
-. www/

대충 짐작을 하더라도 doc, ports, projects, src 프로젝트는 별개의 저장소를 가지고 있음을 알수 있습니다. 이에 반해 NetBSD 진영의 cvsweb.netbsd.org는 다음처럼 꾸며져 있습니다.

cvsweb.netbsd.org
-. htdocs/
-. othersrc/
-. pkgsrc/
-. src/
-. xsrc/

FreeBSD 진영과는 다르게 CVSROOT/ 가 보이질 않습니다. 이러한 구성은 cvsweb과 관련이 있는데 약간의 trick을 이용하면 원하는 프로젝트만 보이게끔 할수가 있습니다. 사실 이것 역시 조금의 삽질을 통해서 알아내었는데 어찌되었든 결론은 프로젝트 성격별로 CVS 저장소를 마련하는 것이 가장 좋은 방법입니다. 그리고 개별 저장소에 대해서 관리 계정을 다르게 가져가는 것도 가능하지만 제가 관리하는 CVS 저장소는 그렇게까지 복잡하지는 않아서 관리계정은 앞에서 언급한 cvs 유저 계정만으로 충분하다고 판단됩니다.

3. pserver 설정

Don't use pserver. use ssh instead.
ssh 사용을 위해서 /etc/rc.conf에 ssh=YES를 추가합니다.

# /etc/rc.d/sshd start


webcvs 설정
-----------
1. webcvs 설치
앞에서 살펴본 cvs 설정만으로 cvs 사용하는데는 아무런 지장이 없지만 cvs 파일에 대한 기록 내용이나 이전 파일과의 diff를 볼때 webcvs를 주로 사용하므로 전 무조건 설치합니다. 그리고 cvsgraph없는 webcvs는 김빠진 콜라와 같으므로 이것 역시 설치합니다. 따라서 webcvs를 설정하기 위해서는 다음으로 요약할수 있습니다.

apache + webcvs + cvsgraph

각 패캐지마다 의존하는 패키지가 있으므로 실제로는 이것보다 많습니다. 가장 손쉬운 방법은 의외로 소스를 통해 build하는 방법이므로 우선 pkgsrc를 checkout해서 make해서 모두 설치합니다.

2. webcvs 설정
linux에 webcvs를 설정할때는 손이 많이 갔었는데 NetBSD에 설치할때는 apache 패키지의 기본 설정 디렉토리에 cgi 및 설정 파일이 위치하게끔 webcvs 패키지가 꾸며져 있어서 별로 할 일이 없습니다.

-. /usr/pkg/etc/httpd/httpd.conf
손 봐야야 할 부분 없음

-. webcvs icons 파일 복사
# cd /usr/pkg/share/httpd/htdocs
(apache Document Root)
# mkdir icons
# cd icons
# cp /usr/pkg/share/examples/cvsweb/icons/* .

-. cvsweb.css 파일 복사
# cd /usr/pkg/share/httpd/htdocs
(apache Document Root)
# mkdir css
# cd css
# cp /usr/pkg/share/examples/cvsweb/css/cvsweb.css .

-. /usr/pkg/libexec/cgi-bin/cvsweb.cgi
손 봐야야 할 부분 없음

-. /usr/pkg/etc/cvsweb/cvsweb.conf
# vi /usr/pkg/etc/cvsweb/cvsweb.conf

@CVSrepositories 에 경로 추가
'local' => ['Local Repository', '/home/cvs'],

-. /usr/pkg/etc/cvsgraph.conf
손 봐야야 할 부분 없음



프로젝트 추가
-------------
프로젝트 추가는 항상 CVS 저장소의 cvs 관리 계정으로 수행하고, 프로젝트는 원하는 프로젝트 카테고리 하위에 추가하는 것으로 하였습니다.

# mkdir /var/cvswork
# chown -R cvs:cvs /var/cvswork
(cvs 관리 계정에 대한 work 디렉토리 생성)
# su - cvs
% cd /var/cvswork/
% mkdir ${project}
% cd ${project}
% ... add source files...
% cvs -d /var/cvs/${projectcategory}-cvsroot import -m " " ${project} ${project} initial
% ...import 확인...
% cd /var/cvswork
% rm -rf ${project}
% cd
% ln -s /var/cvs/${projectcategory}-cvsroot/${project} ${project}

USAGE. ${projectcategory} 는 원하는 프로젝트 카테고리 이름
${project} 는 원하는 프로젝트 이름


CVS test
--------
위의 단계까지 하였으면 우선 cvs 관련한 설정은 모두 끝난 것으로 보이는데 이제는 test하는 것만 남았습니다. 카테고리명은 test-cvsroot로 하고 프로젝트명은 test로 하였습니다.

1. test 카테고리 저장소 생성
# su - cvs
% cd /var/cvs
% mkdir test-cvsroot
% chmod ug+rwx test-cvsroot
% cd test-cvsroot
% cvs -d /var/cvs/test-cvsroot init
(/var/cvs/test-cvsroot/CVSROOT 생성 확인)

2. test 프로젝트 생성
# su - cvs
% cd /var/cvswork
% mkdir test
% cd test
% cvs -d /var/cvs/test-cvsroot import -m " " test test initial

No conflicts created by this import

% cd /var/cvswork
% rm -rf test

3. test 프로젝트를 webcvs에 등록
# su - cvs
% cd
% ln -s /var/cvs/test-cvsroot/CVSROOT CVSROOT-test
% ln -s /var/cvs/test-cvsroot/test test

4. cvs 사용 계정으로 checkout 및 commit 테스트
% ... cvs 사용 계정으로 로그온 ...
% cd
% mkdir work
% cd work
% setenv CVSROOT /var/cvs/test-cvsroot
% cvs co test
% vi hello.c
#include

int main(void)
{
printf("Hello, World!\n");
return 0;
}
%
% cvs add hello.c
cvs add: scheduling file `hello.c' for addition
cvs add: use 'cvs commit' to add this file permanently
% cvs commit -m "add hello.c file" hello.c
RCS file: /var/cvs/test-cvsroot/test/hello.c,v
done
Checking in hello.c;
/var/cvs/test-cvsroot/test/hello.c,v <-- hello.c initial revision: 1.1 done % 5. remote machine에서 ssh를 통한 접근 테스트 % setenv CVSROOT :ext:${username}@${cvsserverip}:/var/cvs/test-cvsroot % setenv CVS_RSH ssh % cd work % cvs co test The authenticity of host 'xxx.xxx.xxx.xxx' can't be established. RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'xxx.xxx.xxx.xxx' (RSA) to the list of known hosts. Password: <...Input Password...>
cvs checkout: Updating test
U test/hello.c
%

USAGE. ${username}은 cvs 사용자 ID, ${cvsserverip}는 CVS Server IP


CSS 적용전


CSS 적용후

프로젝트 등록후


cvsgraph



요약
----
CVS 저장소를 프로젝트 성격별로 하나씩 만들어서 카테고리를 만들고 그 하위에 프로젝트를 추가하는 방식을 사용하였습니다. 그리고 /home/cvs는 단지 해당하는 저장소의 링크를 추가하는 방식으로 웹을 통하여 사용자가 볼수 있도록 허용하였습니다. 즉, 보여주고 싶은 프로젝트만 골라서 보여주는 방식을 사용했습니다. 아마 netbsd의 webcvs가 CVSROOT는 보이지 않고 단지 프로젝트(htdocs, othersrc, pkgsrc, src, xsrc) 만 보이는 것은 이런 방법을 쓰지 않았나 추측해봅니다. 추측을 더욱 가능하게 한 것은 freebsd의 webcvs를 보면 더욱 확신이 드는데 CVSROOT를 CVSROOT-doc 등으로 이름을 바꾸게 되면 cvs 저장소가 제대로 인식을 하지 않는 것으로 알고 있고 또 저렇게 한 화면에 여러 cvs 저장소를 보이게 할려면 dummy directory에 저장소를 symbolic link시키는 방식으로 해야지만 가능합니다.

이렇게 했을때 딱 하나가 불가능한데 cvspserver가 그것입니다. cvspserver 설정시 --allow-root
옵션에서 CVSROOT를 설정하게 되어있는데 이와같이 여러개의 CVS 저장소를 쓰는 경우에는 하나만 사용이 가능합니다.

CVS 백업은 저장소 단위로 가능할 것으로 보이고 저장소별로 remote machine에 sync하는 방식도
가능 할 것으로 보입니다.


Reference
---------
-. Setting up a CVS repository - the FreeBSD way
(http://www.freebsd.org/doc/en_US.ISO8859-1/articles/cvs-freebsd/index.html)
-. cvsweb.freebsd.org
-. cvsweb.netbsd.org

2007년 8월 26일 일요일

NetBSD with KDE 삽질기

TS-7200에 Quick CAM 포팅하려다 잘 안되어서 머리도 식힐겸해서 NetBSD에 KDE를 설치해 보았습니다.

요즘 Ubuntu Linux가 linux 진영에서 하나의 trend로써 전세계적으로 많이 사용되고 있는데 시험삼아 Ubuntu와 Kbuntu를 설치해서 GNOME과 KDE를 한번 비교해봤습니다. FreeBSD를 쓸때에는 Window Maker 이외에는 써보질 않았고 요즘 다시 쓰고 있는 NetBSD 3.1은 XFCE를 사용하고 있는터라 솔직히 GNOME과 KDE가 얼마나 많이 변해왔는지 궁금하기도 하고 2년 넘게 개발 머신으로 사용하고 있는 linux가 현재는 배포되고 있지않은 Wow Linux라서 차기 linux를 선택할 때가 되었다는 생각이 들어 요즘 고르고 있는 중입니다.

Ubuntu 계열 좀 더 정확히 말하면 Debian 계열의 Linux의 장점은 aptitude를 이용한 손쉬운 바이너리 업데이트에 있는데 거기에다 깔끔한 설치화면을 가미하고 CLI환경을 사용자에게 감추는 방식을 사용해서 처음 접하는 사용자에게 그리 어렵지 않게 다가갈수 있도록 배려한 점은 높이 살만합니다.

그래서 이번 기회에 x86계열의 노트북에 VMWare로 NetBSD를 설치할때 순수 바이너리 인스톨만 가지고 얼마나 깔끔한 환경을 제공할 수 있는지 삽질아닌 삽질(?)을 해보았습니다. OS 설치하는 것을 개인적으로 상당히 싫어하는 편이지만 설치할 때 이것 저것 처음 접하는 장면은 화면 캡쳐를 많이 해 두는 버릇이 있어 요번에 설치할때 캡쳐한 화면을 가지고 글을 하나 써보려고 합니다.

목적: KDE 데스크탑 환경으로서의 NetBSD 사용
목표: pkgsrc(2007Q2) 바이너리만 가지고 NetBSD 설치하기
환경: x86 VMWare(WinXP Home), 256MB RAM, 20GB

pkg_add 명령으로 remote에 있는 package를 설치할 수 있는 방법은 PKG_PATH 변수를 이용해서 설치하는 방법이 있는데 예를 들어 다음과 같이 할수 있습니다.(pkg_add(1))

# export PKG_PATH=ftp://ftp.NetBSD.org/pub/NetBSD/packages/2.0/i386/All
# pkg_add -v firefox

dependant한 패키지가 있는 경우 자동으로 설치가 되는데 FreeBSD 만큼 매끄럽게 설치되지가 없습니다. 그래서 하는 수 없이 수동으로 ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/i386/3.1_2007Q2/All 에 있는
패키지를 다운로드 받아서 설치하는 방법을 사용했습니다. 그리고 설치하면서 알게 된 사실인데 이 경우에도 dependant한 패키지가 로컬 디렉토리(정확히는 pkg_add를 수행하는 디렉토리)에 있는 자동으로 매끄럽게 설치가 됩니다.

우선 제일 먼저 설치하는 메뉴에서 모든 set를 설치해서 X도 같이 설치 될수 있게끔 했습니다. 그리고 설치후 에는 제가 좋아하는 xdm이 기동 될수 있는 환경으로 꾸몄습니다.

netbsd: {91} cd /etc
netbsd: {92} pwd
/etc
netbsd: {93} diff -bu ttys.orig ttys
--- ttys.orig 2007-08-25 10:17:17.000000000 +0900
+++ ttys 2007-08-25 10:19:53.000000000 +0900
@@ -9,6 +9,7 @@
ttyE1 "/usr/libexec/getty Pc" vt220 on secure
ttyE2 "/usr/libexec/getty Pc" vt220 on secure
ttyE3 "/usr/libexec/getty Pc" vt220 on secure
+ttyE4 "/usr/libexec/getty Pc" vt220 off secure # manual add...
tty00 "/usr/libexec/getty std.9600" unknown off secure
tty01 "/usr/libexec/getty std.9600" unknown off secure
tty02 "/usr/libexec/getty std.9600" unknown off secure


netbsd: {101} pwd
/etc/X11/xdm
netbsd: {102} diff -bu Xaccess.orig Xaccess
--- Xaccess.orig 2007-08-25 16:33:58.000000000 +0900
+++ Xaccess 2007-08-25 16:34:34.000000000 +0900
@@ -45,7 +45,7 @@
# right hand sides can match.
#

-#* #any host can get a login window
+* #any host can get a login window

#
# To hardwire a specific terminal to a specific host, you can
@@ -63,7 +63,7 @@
# so this may not work in all environments.
#

-#* CHOOSER BROADCAST #any indirect host can get a chooser
+* CHOOSER BROADCAST #any indirect host can get a chooser

#
# If you'd prefer to configure the set of hosts each terminal sees,


netbsd: {104} pwd
/etc/X11/xdm
netbsd: {105} diff -bu xdm-config.orig xdm-config
--- xdm-config.orig 2007-08-25 16:36:26.000000000 +0900
+++ xdm-config 2007-08-25 16:36:32.000000000 +0900
@@ -30,4 +30,4 @@

! SECURITY: do not listen for XDMCP or Chooser requests
! Comment out this line if you want to manage X terminals with xdm
-DisplayManager.requestPort: 0
+!!DisplayManager.requestPort: 0


netbsd: {113} pwd
/etc/X11
netbsd: {114} cat XF86Config
Section "ServerLayout"
Identifier "XFree86 Configured"
Screen 0 "Screen0" 0 0
InputDevice "Mouse0" "CorePointer"
InputDevice "Keyboard0" "CoreKeyboard"
EndSection

Section "Files"
RgbPath "/usr/X11R6/lib/X11/rgb"
ModulePath "/usr/X11R6/lib/modules"
FontPath "unix/:7100"
# FontPath "/usr/X11R6/lib/X11/fonts/misc/"
# FontPath "/usr/X11R6/lib/X11/fonts/Speedo/"
# FontPath "/usr/X11R6/lib/X11/fonts/Type1/"
# FontPath "/usr/X11R6/lib/X11/fonts/CID/"
# FontPath "/usr/X11R6/lib/X11/fonts/75dpi/"
# FontPath "/usr/X11R6/lib/X11/fonts/100dpi/"
# FontPath "/usr/X11R6/lib/X11/fonts/TTF/"
# FontPath "/usr/pkg/lib/X11/fonts/TTF/"
# FontPath "/usr/pkg/lib/X11/fonts/local/"
EndSection
Section "Module"
Load "extmod"
Load "glx"
Load "dbe"
Load "record"
Load "xtrap"
Load "type1"
Load "speedo"
Load "xtt"
EndSection
Section "InputDevice"
Identifier "Keyboard0"
Driver "keyboard"
EndSection

Section "InputDevice"
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "wsmouse"
Option "Device" "/dev/wsmouse"
Option "ZAxisMapping" "4 5"
EndSection

Section "Monitor"
Identifier "Monitor0"
VendorName "Monitor Vendor"
ModelName "Monitor Model"
# HorizSync 31.5 - 35.1
# VertRefresh 50.0 - 70.0
Option "DPMS"
EndSection

Section "Device"

### Available Driver options are:-
### Values: : integer, : float, : "True"/"False",
### : "String", : " Hz/kHz/MHz"
### [arg]: arg optional
#Option "HWcursor" # []
#Option "NoAccel" # []
Identifier "Card0"
Driver "vmware"
VendorName "VMware Inc"
BoardName "[VMware SVGA II] PCI Display Adapter"
BusID "PCI:0:15:0"
EndSection

Section "Screen"
Identifier "Screen0"
Device "Card0"
Monitor "Monitor0"
DefaultDepth 16
SubSection "Display"
Viewport 0 0
Depth 16
Modes "1024x768"
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 1
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 4
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 8
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 15
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 16
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 24
EndSubSection
EndSection


netbsd: {120} pwd
/etc
netbsd: {121} cat rc.conf
...
hostname=netbsd.myhome
defaultroute="172.20.10.1"
sshd=YES

xfs=YES
xdm=YES xdm_flags=""


netbsd: {124} pwd
/etc
netbsd: {125} cat ifconfig.pcn0
up
172.20.1.8 netmask 255.255.0.0 media autoselect

netbsd: {126} pwd
/etc
netbsd: {127} cat hosts
...
172.20.1.8 netbsd netbsd. netbsd.myhome


여기까지하면 X와 ethernet 설정은 어느정도 마무리가 되었고 추가적으로 차후 pkgsrc 컴파일시 편리하게
하기 위해서 저는 sudo 를 설치하여 사용합니다.

netbsd: {136} pwd
/usr/pkg/etc
netbsd: {137} diff sudoers.orig sudoers
25c25
< # %wheel ALL=(ALL) NOPASSWD: ALL --- > %wheel ALL=(ALL) NOPASSWD: ALL


netbsd: {143} pwd
/etc
netbsd: {144} cat mk.conf
.if exists(/usr/pkg/bin/sudo)
SU_CMD= /usr/pkg/bin/sudo /bin/sh -c
.endif

이렇게 하고 난 다음 .xinitrc 는 다음 처럼 편집합니다.
netbsd: {145} cd
netbsd: {145} touch .xinitrc
netbsd: {145} ln .xinitrc .xsession
netbsd: {145} cat .xinitrc
#!/bin/sh
# $Xorg: xinitrc.cpp,v 1.3 2000/08/17 19:54:30 cpqbld Exp $

userresources=$HOME/.Xresources
usermodmap=$HOME/.Xmodmap
sysresources=/etc/X11/xinit/.Xresources
sysmodmap=/etc/X11/xinit/.Xmodmap

# merge in defaults and keymaps

if [ -f $sysresources ]; then
xrdb -merge $sysresources
fi

if [ -f $sysmodmap ]; then
xmodmap $sysmodmap
fi

if [ -f $userresources ]; then
xrdb -merge $userresources
fi

if [ -f $usermodmap ]; then
xmodmap $usermodmap
fi

# start some nice programs

### nabi ###
export LANG=ko_KR.UTF-8
export XMODIFIERS="@im=nabi"
nabi &

### kde ###
startkde

여기까지 오면 이제 설정은 다 끝난 것으로 보이는데 다시 재부팅을 하면 xdm 환영 메시지가 나옵니다.
개인적으로 Xmanager와 같은 프로그램으로 연결을 하는 것을 좋아하기 때문에 xdm이 안 떠 있으면 X 쓰는
기분이 나질 않습니다^^



01) KDE 설치 완료후 첫 페이지(설정 화면)


02) 설정 완료후 처음 보게 되는 화면


03) KDE 설치에 따른 pkg_info 리스트


04) KDE 기본 fonts


05) 아무런 설정없이 nabi 실행(.xinitrc 에 nabi 설정을 하지 않은 경우)


06) mlterm 실행



07) misc 설치(qt4, gtk+, OpenOffice2 ...)


08) GTK+2 개발 환경 테스트


09) QT4 개발 환경 테스트


10) gimp 설치 및 실행(실행이 되지 않음)


11) gtkmm 설치 및 개발 환경 테스트


12) nabi와 한글 입력 테스트


13) KDE logout


NOTE.
qt4 설치시 문제가 있는데 2007.08.26 현재 2007Q2 바이너리를 설치하면 안됩니다.
대신 2007Q1의 패키지를 설치해야 합니다. 2007Q2의 qt4-libs-4.2.3nb1에 Xml과 같은 라이브러리가
빠져 있어 designer, assistant와 같은 프로그램(qt4-tools-4.2.3)이 실행되지 않습니다. 더군다나
2007Q2에는 qt4-tools가 빠져있습니다. 따라서 다음 패키지는 2007Q1의 것을 이용했습니다.

qt4-libs-4.2.3nb1 C++ X GUI toolkit
qt4-tools-4.2.3 QT GUI (WYSIWYG) builder and other tools
qt4-docs-4.2.3 Documentation for the QT C++ X GUI toolkit

Conclusion:
4GB 가 조금 넘는 양을 설치하고서야 위의 모든 기능이 설치가 되었는데 Kbuntu는 2GB 가 조금 넘는 크기를 가집니다. Kbuntu의 경우 개발 환경이 배제된 상태에서 이정도를 차지 하므로 사실상 설치 크기를 비교한다는 것은 아무런 의미가 없습니다. 패키지는 거의 200개에 육박할 정도로 설치가 되었는데 한가지 아쉬운 것은 KDE에서 처음 지향한 개발 모델에서 한가지 유감스러운 감이 있습니다. 라이브러리가 지나치게 많이 설치되는 문제가 있는데 이는 처음 KDE 프로젝트를 시작할 때 메일링리스트에 올린 글을 참조한다면 거의 해결하지 못했다는 느낌이 듭니다. 아무래도 오픈 소스의 가장 큰 딜레마가 아닐까 합니다.

데스크탑 OS로서의 NetBSD. 아주 쓸만합니다!

2007년 8월 20일 월요일

KDE vs GNOME

또 약간은 현 게시판 성격에 맞지 않는 글이지만 요즘 제가 GUI toolkit에 맛을 들여서 헤어나오질 못하고 있습니다. 간단하게 두가지를 비교해 보았는데요, 비교는 그나마 객관적으로 하기 위해서 초기 프로젝트를 시작할때 리더가 메일링 리스트에 올린 글을 가지고 비교해 보았습니다.


http://groups.google.com/group/comp.os.linux.misc/tree/browse_frm/thread/4836e257721ab7fb/cb4b2d67ffc3ffce?rnum=1&_done=%2Fgroup%2Fcomp.os.linux.misc%2Fbrowse_frm%2Fthread%2F4836e257721ab7fb%2F10e10a7a9e08943b%3Flnk%3Dgst%26#doc_cb4b2d67ffc3ffce

http://mail.gnome.org/archives/gtk-list/1997-August/msg00123.html

Q. what is NOT a GUI
A. KDE
- X Window System
- widget: motif, athena, ...
- Window manager
A. GNOME
- There is no assumption.

Q. Goals
A. KDE
- A GUI for endusers
A. GNOME
- a free and complete set of user friendly applications and desktop tools

Q. which toolkit to choice to develop
A. KDE
- Qt
A. GNOME
- GTK toolkit

Q. Programming language(base language)
A. KDE
- C++
A. GNOME
- C

사실 두가지 프로젝트의 공통점이 상당히 많은데 그 중 가장 대표적인 것이라고 한다면 모든 것을 다시 만들어가는 방식이 아닌 기존에 만들어져 있는 toolkit을 그대로 이어가가는 방식을 택했습니다. 여기에서 base 언어가 되는 C, C++ 때문에 Qt의 라이센스 보다는 이것가지고 양측의 설전이 아직도 오고가고 있습니다. 개인적인 생각으로는 라이센스 문제를 생각하자면 일반적으로 생각하는 것과는 다르게 KDE 진영이 훨씬 유리하다고 봅니다. Full time으로 Qt 라이브러리에 회사 운명을 건 TrollTech라는 회사가 든든한 버팀목이 되어주는 것에 비해 RedHat은 GNU 라이센스를 오픈 소스에 적용하고 있지만 Fedora, GNOME 에 대한 지원이 많이 부족한 것으로 보이고 프로젝트 역시 조금은 매끄럽게 진행되지 못한다는 느낌이 듭니다. 초기 RedHat 배포본을 만들던 초심을 가지고 GNOME 프로젝트를 지원한다면 하는 아쉬움이 있습니다.

그리고 두 프로젝트의 초기 경쟁자는 KDE도 GNOME도 아닌 Motif로 대변되는 CDE 진영이라는 사실이 조금은 낯설게 느껴집니다. KDE 진영은 위에서 언급한바와 같이 단순한 toolkit은 GUI가 될수없다는 논리를 펴고 있고 프로젝트 처음 공포시 CDE가 존재하긴 했지만 늦은감이 없지않아 그 틈새 시장을 비집고 들어간 것이라봐야 될 것이고, GNOME 진영 역시 KDE 보다 1년 뒤늦게 시작했지만 경쟁자로서 CDE가 존재한다는 것은 모를리가 없었을 겁니다.

Qt vs GTK 라고 하면 조금 이야기가 달라지겠지만 지금은 KDE와 GNOME의 비교를 하는 것이니 한가지 더 짚고 갈 것이 있는데 이는 지향하고자 하는 방향이 사뭇 다릅니다. 이는 enduser뿐만아니라 developer를 두 진영으로 나누게 되는 계기도 되는데 KDE는 Qt라고 하는 단일 toolkit으로 모든 것을 해결하려고 하고 있고 GNOME진영은 가능한 visual element를 잘게 나누어서 서로 공유하자는 방향으로 나아가고 있습니다. 이는 11년째를 맞고 있는 KDE와 올해 10년째를 맞고 있는 GNOME(GNOME 탄생일이 재미있게도 8월 15일 입니다.) 이 한결같이 지켜오고 있습니다. 단적인 예로 Qt는 FTP, TELLET과 관련된 컴포넌트가 존재합니다. 그리고 addon으로 찾아보면 RS-232 통신에 관련된 컴포넌트도 존재합니다. 하지만 GNOME의 toolkit에는 그러한 것이 존재하지 않습니다. UNIX의 초기 철학을 잘 반영하는 것이 GNOME 진영인 것은 확실합니다. 하지만 Qt와는 반대로 너무나도 여러개로 나뉘어 있는 GNOME toolkit(GLib, GObject, Pango, ATK, GdkPixbuf, GDK, GTK) 들이 별개로 업데이트 되고 있는 현실이고 또한 각 toolkit 별로 버전번호도 상이해서 enduser입장에서 meta-package로 설치하는 GNOME toolkit을 생각할 때 이부분은 반드시 해결해야 할 숙제라고 봅니다. 다행히 GNOME 진영의 developer 사이에서 이 부분에 대한 검토가 이루어지고 있는 것으로 보아 조만간에 좋은 소식을 접할수 있을 것으로 기대합니다.

현실적인 문제라고 봐야할지는 모르겠지만 1년 늦게 시작한 GNOME이 KDE에 비해 조금은 뒤쳐지는 것은 저만 느끼는 것인가요. 항상 KDE에서 먼저 소개되고 이후에 같은 것이 GNOME에 소개되는 것을 보면 중앙집중적으로 발전해나가는 KDE의 개발 전술을 따라 잡기는 역부족이 아닌가 싶습니다.

마지막으로 위의 두 프로젝트와는 별개로 BSD License를 가지고 시작하는 프로젝트가 하나 있습니다. E17이라고 명명한 enlightenment 진영의 약진이 그것인데요, 개발의 방향은 GNOME과 비슷합니다. 즉 toolkit의 다양화(diverse)로 기존의 enlightenment를 새롭게 재탄생시키고자 많은 노력을 하고 있습니다. 초기 window manager 의 프로젝트가 현 3세대의 KDE, GNOME, XFCE 진영의 삼국 시대를 사국 시대로 만들어 갈 수 있을지 자뭇 기대가 됩니다.

OOP에 대한 통사론(syntax)적 풀이

현재 게시판의 제목과는 조금 상관없는 주제의 글인데 GTK+ 공부하다 생각이 나서 한번 적어봅니다.

Object Oriented Programming

번역 => 객체(개체) 지향(위주) 프로그래밍

영어의 통사론(syntax) 입장에서 보자면,

Programming object oriented
(Verb) (noun) (adj)
| | |
| +---+---+
| |
+------------+

이 문장의 주요소는 programming 인데 이를 도치시킨 문장이 OOP입니다.

Object oriented programming

즉, object라는 단어를 문장의 주요소로 만들기 위해 도치 시켰습니다.

왜 도치 시켰을까요?

Object라는 단어를 강조시키기 위함인 것은 자명한데 여기서 OOP를 구현한 프로그램 소스를 보면 재미있는 걸 발견할수 있습니다.

다음은 Qt에서 발췌한 문장인데 다음과 같습니다.

window->setWindowTitle("Hello, World");

우리가 알고 있는 token 또는 identifier 라는 것으로 분류하자면 다음 처럼 될겁니다.

window -> setWindowTitle ("Hello, World") ;
| | |
| | |
| | +---- verb
| |
| +--- adj(oriented)
|
+-- noun

Object oriented programming
(none) (adj) (verb)

와 문장의 순서가 동일!

-> 연산자를 adjective로 분류한것은 조금 억지스러운 맛이 없지는 않지만 oriented란 단어의 뜻과 -> 의 기호적인 의미를 생각한다면 어느정도 저의 의견에 수긍할 것으로 보입니다.

한가지 더 제시하자면 setWindowTitle ("Hello, World") ; 의 문장 구성 요소인데 이는 자연언어로 조금 바꾼다면 아마 다음과 같을 것입니다.

setWindowTitle ("Hello, World") ;
| | +------+
| +---------+ |
| | |
/ / /
set window title that is 'Hello, World'.
^^^^^^^

알다시피 두 문장을 연결할때 관계대명사 that과 동사 is 를 보통 생략합니다. 위에서와 마찬가지로 컴퓨터 언어로 써내려간 소스에서도 이와 같은 문법이 동일하게 적용됩니다. 하지만 C에서는 관계대명사를 명시적으로 지정을 해주어야 합니다.

gtk_window_set_title(GTK_WINDOW(window), "Hello, World");

조금 억지스럽게 짜맞추자면 C로 구현한 OOP는 OOP가 아니라 POO에 가깝습니다. 즉, 동사역할을 하는 function name이 항상 먼저 오게 되어있습니다. 따라서 C++와는 다르게(C++에서는 Object 가 보통 문장 제일 앞에 옵니다.) Object가 없기 때문에 관계대명사 역할을 하는 요소를 반드시 function의 argument로 전달해 주어야 합니다. 이경우에는 관계대명사 와 목적어 역할을 둘 다 하는 what 정도가 되겠네요.

이상 영어의 syntax(통사론)을 가지고 OOP를 조금 다르게 해석해 봤습니다.

Q. Why not Subject oriented programming?
클래스의 인스턴스라는 의미로 쓰이는 Object라는 단어 대신 Subject라는 단어를 쓰지 않은 이유는 뭘까?

2007년 8월 13일 월요일

Serial COM 포트 사용하기

우선 기본적으로 내장되어 있는 Serial Port는 COM1, COM2가 존재하는데 COM1은 일반적으로 콘솔용으로 사용하고 COM2를 serial interface용으로 사용할 수 있습니다. 하드웨어 설명서에 나온대로 본다면,

+---+---+---+---+---+
TX-RX-NC NC TX-
+---+---+---+---+---+
TX+RXDTXDRX+GND
+-------------------+

그런데 기본적으로 COM2는 RXD, TXD, GND만 사용하도록 되어있습니다. RS-485지원할려면 조금 번거로운 작업을 거쳐야 됩니다. 세개의 선만을 연결해서 크로스 케이블을 만듭니다.

이제 테스트만 남았는데 그전에 시리얼 포트에 대한 디바이스 이름을 살펴보면,

in Linux, /dev/ttyAM0(/dev/console), /dev/ttyAM1
in NetBSD, /dev/epcom0(/dev/console), /dev/epcom1

NetBSD에서 디바이스 이름을 몰라서 조금해멨는데 http://www.netbsd.org/ports/evbarm/ 에 이렇게 되어있네요.

Support for the TS-7200 was written by Jesse Off

* On-CPU RS232 UARTs (2) (epcom)

ts-7200# dmesggrep epcom
epcom0 at epsoc0 addr 0x808c0000-0x808c0fff intr 52
epcom0: console
epcom1 at epsoc0 addr 0x808d0000-0x808d0fff intr 54

NetBSD를 설치했을때 epcom* 디바이스가 /dev 에 없어서 다음처럼 디바이스를 생성시켜줍니다.

ts-7200# sh /dev/MAKEDEV epcom0
ts-7200# sh /dev/MAKEDEV epcom1
ts-7200# ls -al /dev/epcom*
crw------- 1 uucp wheel 107, 0 Aug 13 16:05 /dev/epcom0
crw------- 1 uucp wheel 107, 1 Aug 13 16:05 /dev/epcom1
ts-7200# chmod g+rw /dev/epcom*
ts-7200# ls -al /dev/epcom*
crw-rw---- 1 uucp wheel 107, 0 Aug 13 16:05 /dev/epcom0
crw-rw---- 1 uucp wheel 107, 1 Aug 13 16:05 /dev/epcom1

사실상 필요한 것은 /dev/epcom1이고 적절히 권한을 부여합니다. 이 경우에는 user, group에 대해서 read,
write를 할수 있게 했습니다.

이제 테스트 수행만 남았는데 간단하게 tx, rx할수 있는 프로그램을 만들어서 테스트를 해보았습니다.

결과)
ESP-NS(linux) -> TS-7200(NetBSD) : 수신측 TS-7200 보드에서는 8byte, 5byte씩 나누어져서 read된다.
TS-7200(NetBSD) -> ESP-NS(linux) : 수신측 ESP-NS 보드에서 가끔 8byte, 5byte씩 나누어져서 read된다.

Q) 수신 버퍼가 8byte씩 읽어지는 것으로 보입니다. How to increase read buffer? 궁금합니다.

아래 소스

/*
* $Id: txrx.c,v 1.1 2007/08/13 08:04:40 pjy Exp $
*/
#include
#include
#include
#include

typedef struct
{
char speed[20]; /* 1200, 2400, 9600, 19200, 38400 */
char data_bit[20]; /* 5, 6, 7, 8 */
char parity[20]; /* NO, EVEN, ODD */
char stop_bit[20]; /* 1, 2 */
char control[20]; /* NO, Xon/Xoff */
} COMMSET_DS;

struct termios INIT_SETTING;

int setTTY(char*, char*);
int restoreTTY(int, const struct termios*);
int getCommSet(char*, COMMSET_DS*);
void prnCommSet(char*, char*, COMMSET_DS);
void getString(char*, const char*, int, char*);

int main(int argc, char *argv[])
{
int fd, len;
char buf[1024];

if(argc != 4) {
fprintf(stderr, "Usage: %s flag(1:tx, other:rx) device set\n", argv[0]);
fprintf(stderr, " flag: 1(tx), other(rx)\n");
fprintf(stderr, " device: /dev/ttyS03 ~ /dev/ttyS06(ESP-NS linux)\n");
fprintf(stderr, " device: /dev/ttyAM0 ~ /dev/ttyAM1(TS-7200 linux)\n");
fprintf(stderr, " device: /dev/epcom0 ~ /dev/epcom1(TS-7200 NetBSD)\n");
fprintf(stderr, " set: speed:data bit:parity:stop bit:control\n");
fprintf(stderr, " ex) in ESP-NS board(linux)--->\n");
fprintf(stderr, " tx-> %s 1 /dev/ttyS05 115200:8:NO:1:NO\n", argv[0]);
fprintf(stderr, " rx<- %s 2 /dev/ttyS05 115200:8:NO:1:NO\n", argv[0]); fprintf(stderr, " ex) in TS-7200 board(linux)--->\n");
fprintf(stderr, " tx-> %s 1 /dev/ttyAM1 115200:8:NO:1:NO\n", argv[0]);
fprintf(stderr, " rx<- %s 2 /dev/ttyAM1 115200:8:NO:1:NO\n", argv[0]); fprintf(stderr, " ex) in TS-7200 board(NetBSD)--->\n");
fprintf(stderr, " tx-> %s 1 /dev/epcom1 115200:8:NO:1:NO\n", argv[0]);
fprintf(stderr, " rx<- %s 2 /dev/epcom1 115200:8:NO:1:NO\n\n", argv[0]); return 1; } fd = setTTY(argv[2], argv[3]); if(fd < 0) { fprintf(stderr, "Can't set tty.\n"); return 1; } printf("%s Terminal attribute set OK!\n", argv[2]); if(atoi(argv[1]) == 1) { snprintf(buf, sizeof(buf), "Hello, NetBSD"); while(1) { len = write(fd, buf, strlen(buf)); if(len > 0)
printf("send %d bytes: %.*s\n", len, len, buf);
sleep(3);
}
}
else {
while(1) {
len = read(fd, buf, sizeof(buf));
if(len > 0)
printf("read %d bytes: %.*s\n", len, len, buf);
}
}

(void)restoreTTY(fd, &INIT_SETTING);
return 0;
}

int setTTY(char *device, char *comm)
{
struct termios new_settings;
COMMSET_DS commset;
int fd;

printf("---------- %s device set start ----------\n", device);
/********************************************************************
open device and get comm set value
*********************************************************************/
if((fd = open(device, O_RDWR | O_NOCTTY)) < 0) { fprintf(stderr, "Unable to open %s\n", device); return -1; } if(getCommSet(comm, &commset) != 1) { fprintf(stderr, "getCommSet(%s) error\n", comm); return -1; } prnCommSet(device, comm, commset); /******************************************************************** set terminal flag *********************************************************************/ tcgetattr(fd, &INIT_SETTING); new_settings = INIT_SETTING; new_settings.c_iflag &= ~ISTRIP; /* No Character strip */ new_settings.c_iflag |= IGNBRK; /* ignore Break */ #ifdef _TMP_ new_settings.c_iflag |= IGNCR; /* ignore CR */ #endif new_settings.c_iflag &= ~ICRNL; /* no map CR to NL on input */ new_settings.c_iflag &= ~IGNCR; /* enable CR */ new_settings.c_iflag &= ~INLCR; /* no map NL to CR on input */ new_settings.c_iflag |= IGNPAR; /* ignore chars with parity err */ if(!strcmp(commset.control, "NO")) { new_settings.c_iflag &= ~IXON; /* disable input flow control */ new_settings.c_iflag &= ~IXOFF; /* disable output flow control */ printf("NOTE. set flow control flag: disable\n"); } else if(!strcmp(commset.control, "Xon/Xoff")) { new_settings.c_iflag |= IXON; /* enable input flow control */ new_settings.c_iflag |= IXOFF; /* enable output flow control */ printf("NOTE. set flow control flag: Xon/Xoff\n"); } else { new_settings.c_iflag &= ~IXON; /* disable input flow control(default) */ new_settings.c_iflag &= ~IXOFF; /* disable output flow control(default) */ printf("NOTE. set flow control flag: disable(default)\n"); } if(!strcmp(commset.parity, "NO")) { new_settings.c_cflag &= ~PARENB;/* no parity */ printf("NOTE. set parity flag: no parity\n"); } else if(!strcmp(commset.parity, "EVEN")) { new_settings.c_cflag |= PARENB; /* enable parity */ new_settings.c_cflag &= ~PARODD;/* even parity */ printf("NOTE. set parity flag: even parity\n"); } else if(!strcmp(commset.parity, "ODD")) { new_settings.c_cflag |= PARENB; /* enable parity */ new_settings.c_cflag |= PARODD; /* odd parity */ printf("NOTE. set parity flag: odd parity\n"); } else { new_settings.c_cflag &= ~PARENB; /* no parity(default) */ printf("NOTE. set parity flag: no parity(default)\n"); } new_settings.c_cflag &= ~CSIZE; if(!strcmp(commset.data_bit, "5")) { new_settings.c_cflag |= CS5; /* set 5bits/char */ printf("NOTE. set data bit flag: 5bits/char\n"); } else if(!strcmp(commset.data_bit, "6")) { new_settings.c_cflag |= CS6; /* set 6bits/char */ printf("NOTE. set data bit flag: 6bits/char\n"); } else if(!strcmp(commset.data_bit, "7")) { new_settings.c_cflag |= CS7; /* set 7bits/char */ printf("NOTE. set data bit flag: 7bits/char\n"); } else if(!strcmp(commset.data_bit, "8")) { new_settings.c_cflag |= CS8; /* set 8bits/char */ printf("NOTE. set data bit flag: 8bits/char\n"); } else { new_settings.c_cflag |= CS8; /* set 8bits/char(default) */ printf("NOTE. set data bit flag: 8bits/char(default)\n"); } new_settings.c_cflag |= CLOCAL; /* ignore modem status lines */ new_settings.c_cflag |= CREAD; /* enable receiver */ if(!strcmp(commset.stop_bit, "1")) { new_settings.c_cflag &= ~CSTOPB; /* 1 stop bit */ printf("NOTE. set stop bit flag: 1 stop bit\n"); } else if(!strcmp(commset.stop_bit, "2")) { new_settings.c_cflag |= CSTOPB; /* 2 stop bit */ printf("NOTE. set stop bit flag: 2 stop bit\n"); } else { new_settings.c_cflag &= ~CSTOPB; /* 1 stop bit(default) */ printf("NOTE. set stop bit flag: 1 stop bit(default)\n"); } #ifdef _TMP_ new_settings.c_oflag &= ~OPOST; /* ouput processing off */ new_settings.c_oflag |= TAB3; /* expand tabs to space */ #endif new_settings.c_lflag &= ~ICANON; /* non-canonical mode */ new_settings.c_lflag &= ~ECHO; /* echo off */ new_settings.c_lflag &= ~ISIG; /* ignore signal from tty */ /*new_settings.c_lflag &= ~IEXTEN;*//* extended input processing off*/ /*new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0;*/ if(!strcmp(commset.speed, "1200")) { /* 1200 bps */ cfsetispeed(&new_settings, B1200); cfsetospeed(&new_settings, B1200); printf("NOTE. set speed flag: 1200 bps\n"); } else if(!strcmp(commset.speed, "2400")) { /* 2400 bps */ cfsetispeed(&new_settings, B2400); cfsetospeed(&new_settings, B2400); printf("NOTE. set speed flag: 2400 bps\n"); } else if(!strcmp(commset.speed, "4800")) { /* 4800 bps */ cfsetispeed(&new_settings, B4800); cfsetospeed(&new_settings, B4800); printf("NOTE. set speed flag: 4800 bps\n"); } else if(!strcmp(commset.speed, "9600")) { /* 9600 bps */ cfsetispeed(&new_settings, B9600); cfsetospeed(&new_settings, B9600); printf("NOTE. set speed flag: 9600 bps\n"); } else if(!strcmp(commset.speed, "19200")) { /* 19200 bps */ cfsetispeed(&new_settings, B19200); cfsetospeed(&new_settings, B19200); printf("NOTE. set speed flag: 19200 bps\n"); } else if(!strcmp(commset.speed, "38400")) { /* 38400 bps */ cfsetispeed(&new_settings, B38400); cfsetospeed(&new_settings, B38400); printf("NOTE. set speed flag: 38400 bps\n"); } else if(!strcmp(commset.speed, "57600")) { /* 57600 bps */ cfsetispeed(&new_settings, B57600); cfsetospeed(&new_settings, B57600); printf("NOTE. set speed flag: 57600 bps\n"); } else if(!strcmp(commset.speed, "115200")) { /* 115200 bps */ cfsetispeed(&new_settings, B115200); cfsetospeed(&new_settings, B115200); printf("NOTE. set speed flag: 115200 bps\n"); } else if(!strcmp(commset.speed, "230400")) { /* 230400 bps */ cfsetispeed(&new_settings, B230400); cfsetospeed(&new_settings, B230400); printf("NOTE. set speed flag: B230400 bps\n"); } else { /* 9600 bps(default) */ cfsetispeed(&new_settings, B9600); cfsetospeed(&new_settings, B9600); printf("NOTE. set speed flag: 9600(default) bps\n"); } /******************************************************************** set terminal type *********************************************************************/ if(tcsetattr(fd, TCSANOW, &new_settings) != 0) { fprintf(stderr, "Could not set attributes\n"); return -1; } printf("%s device has been initialized successfully.\n", device); return fd; } int restoreTTY(int fd, const struct termios *init_setting) { if(tcsetattr(fd, TCSANOW, init_setting) != 0) { fprintf(stderr, "Could not restore terminal attribute\n"); return -1; } return 1; } int getCommSet(char *str, COMMSET_DS *pCommSet) { char tmp[100]; getString(str, ":", 0, tmp); memcpy(pCommSet->speed, tmp, sizeof(pCommSet->speed));
/*printf("0(speed) -> %s, %s\n", tmp, pCommSet->speed);
printf("strlen() = %d\n", strlen(pCommSet->speed));*/
if(strlen(pCommSet->speed) < 1) return 0; getString(str, ":", 1, tmp); memcpy(pCommSet->data_bit, tmp, sizeof(pCommSet->data_bit));
/*printf("1(data_bit) -> %s, %s\n", tmp, pCommSet->data_bit);
printf("strlen() = %d\n", strlen(pCommSet->data_bit));*/
if(strlen(pCommSet->data_bit) < 1) return -1; getString(str, ":", 2, tmp); memcpy(pCommSet->parity, tmp, sizeof(pCommSet->parity));
/*printf("2(parity) -> %s, %s\n", tmp, pCommSet->parity);
printf("strlen() = %d\n", strlen(pCommSet->parity));*/
if(strlen(pCommSet->parity) < 1) return -2; getString(str, ":", 3, tmp); memcpy(pCommSet->stop_bit, tmp, sizeof(pCommSet->stop_bit));
/*printf("3(stop_bit) -> %s, %s\n", tmp, pCommSet->stop_bit);
printf("strlen() = %d\n", strlen(pCommSet->stop_bit));*/
if(strlen(pCommSet->stop_bit) < 1) return -3; getString(str, ":", 4, tmp); memcpy(pCommSet->control, tmp, sizeof(pCommSet->control));
/*printf("4(control) -> %s, %s\n", tmp, pCommSet->control);
printf("strlen() = %d\n", strlen(pCommSet->control));*/
if(strlen(pCommSet->control) < 1) return -4; return 1; } void prnCommSet(char *device, char *comm, COMMSET_DS CommSet) { printf("device : %s\n", device); printf("comm set: %s\n", comm); printf(" -> speed : %s\n", CommSet.speed);
printf(" -> data bit : %s\n", CommSet.data_bit);
printf(" -> parity : %s\n", CommSet.parity);
printf(" -> stop bit : %s\n", CommSet.stop_bit);
printf(" -> control : %s\n", CommSet.control);

return;
}

void getString(char *data, const char *delim, int order, char *str)
{
int k = 0;
char *token, ddd[1024];

strncpy(ddd, data, sizeof(ddd));
*str = 0x00;
token = strtok(ddd, delim);
while(token != NULL) {
if(k++ == order) { /* target string */
strcpy(str, token);
break;
}
token = strtok(NULL, delim); /* get next token */
}
}

/************************************************************************
End of Code
*************************************************************************/

2007년 7월 18일 수요일

X Window System 그리고 MIT 괴짜들

X가 MIT에서 처음 세상에 나온지 이제 20년이 거의 다되어 가는데 X에 관한 문서가 의외로 많이 없다는것이 이상해서 2주 전부터 인터넷을 뒤지고 전에 사두었던 오렐리의 X에 대한 책을 다시 읽으면서 새삼 X Window System이라는것이 기술이라기 보다는 컬트 문화에 가깝다는 생각이 듭니다.

서버/클라이언트 용어부터 우리가 아는 것과는 정반대의 논리를 펼치는 X 패러다임을 시작으로 X 콘소이엄에 참가한 업체들의 기술은 모두 무시하고 MIT 자기들이 만들것을 모조리 표준으로 만들어 버리고, X의 이념에 위배된다며 여러 업체들이 제시한 User interface를 "policy free" 라는 슬로건하에 모두 폐기(?)시킨 후 twm을 기본 Window Manager로 배포본에 포함시킨 전례를 보면 해커라는 용어를 만들어 낸 MIT 답게, 그리고 리차드 스톨맨의 행동과 비슷하게 남들과 타협을 불허하는 그들만의 리그는 에릭 레이몬드의 성당과 시장의 개념을 빌리자면 그들에게 있어 시장은 MIT를 의미하는것으로 보입니다.

KDE, GNOME과 같은 통일화된 User interface를 주장하는 공동체가 생긴지도 꽤 오래되었지만 제가 보기에는 의외로 X에 대해서 아는 사람이 많이 없는 것으로 보입니다. X 관련서적이 모두 90년대 나온것이 고작이고 수량도 그리 많지 않습니다. 웹사이트를 뒤져봐도 개념적인 설명을 한 곳이 거의 없더군요.

이야기가 조금 다른곳으로 흘렀는데, 결론은 MIT 괴짜들이 만든 X를 정상적인 상태로 이해한다는 것은 무리일 것 같고 xxx 같이 이해하는 것이 정답아닐까요 ^^ 그리고 책을 자꾸 보다 보니 내 컴퓨터에 설치된 X에 언제부터인가 Window Manager가 twm으로 바뀌어 있네요. 어찌보면 엔틱스럽고 빈티지 스타일 느낌도 나서 보기 좋네요. 내 컴퓨터에도 복고 바람 ~

ps) 어느 교수님이 이렇게 말씀하시더군요. "기술은 공부하라고 존재하는 것이 아니라 문화 코드를 만들기 위해 존재한다는 것을..."

2007년 7월 13일 금요일

Xfce4 설치

무려 30개 가까이 되는 패키지를 설치하고 나서야 컴파일 설치가 끝나긴 했는데 역시 이미 만들어둔 binary 패키지를 설치하는게 좋을 듯 싶네요.

컴파일 및 설치에 약 1GB 정도가 쓰입니다. 상대적으로 KDE, GNOME에 비해 가벼운 편입니다.

~/.xinitrc

LANG=ko_KR.UTF-8
LC_ALL=ko_KR.UTF-8
LINGUAS=ko_KR.UTF-8

export XMODIFIERS="@im=nabi"
export LANG LC_ALL LINGUAS
export GDK_USE_XFT=1
export G_BROKEN_FILENAMES=1
export GTK_IM_MODULE=hangul2

nabi &
/usr/pkg/bin/startxfce4

ps) 빨리 pkgsrc 가 cross compile 될수 있는 환경이 되었으면 하는 바램이....

2007년 7월 11일 수요일

Qt4 설치 수기

아직 TS-7200 보드에서 X를 띄울수 있는 상황이 아니라서 필요하지는 않지만 요즘 X Window 프로그램을 작성해볼까해서 지난 5일동안 밤잠도 잊은채 웹을 뒤져가며 삽질했던 내용을 적어볼까 합니다.

가장 먼저 알게 된 것은 X 프로그래밍을 하는것이 예전처럼 어렵지않은 환경을 가지고 있었다는 겁니다. 나만 몰랐나 -:( 지금은 데스크탑을 넘어서 이기종간에 포팅도 자유롭고, 더군다나 임베디드 시스템에 까지 손을 뻗고 있으니 세상 참 많이 좋아졌습니다.

취미로 배워볼 생각으로 우선 위도우 매니저가 얼마나 다양해졌는지 한번 살펴봤습니다. http://www.xwinman.org/ 에 잘 정리가 되어 있습니다. 이젠 추억으로 남아 있는 fvwm이 아직도 개발중에 있다는 것이 참 신기하네요. 호기심에 한번 설치해 보았습니다. 역시 빠른 속도에 감탄하고 하지만, 설정파일을 편집하는 것이 너무나 고전적이네요^^ UI도 이제는 먹어주지도 않고... 바로 삭제해버렸습니다. 다음은 Enlightenment. 최근에 E17로 한참 업그레이드 하고 있는 프로젝트인데 상당히 매력적인 부분이 많이 있습니다. 아무래도 이 프로젝트가 이젠 기존의 윈도우 매니저에서 KDE, GNOME 과 같은 레벨로 진화할려는 노력이 보입니다. 개발하는 입장에서는 너무나도 매력적인 프로젝트입니다. 한가지 단점이라면 한글화가 제대로 지원이 안되고 나아가 국제화에 대한 지원을 할 예정인지 알수가 없네요. 조금 아쉽습니다. 이녀석이 성공한다면 우린 또다른 API 공부해야 될지도 모릅니다. 그래도 아직 쓸만한게 있다면 Window Maker를 따라잡을수가 없나봅니다. 현재 개발중단중인것으로 알고 있는데 조금 아쉽습니다.

GTK 는 조금 공부하다 지쳐서 미루어 오다가 최근에 Qt를 접해보았는데 상당한 매력덩어리 입니다. 거부감이 드는것은 라이센스 보다는 Qt의 철학이 조금은 마음에 들지 않습니다. 필요한 라이브러리를 모두 모아 두어서 나중에 여기에 의존할까 두렵습니다. NetBSD에 설치하기 전에 Linux와 Windows에 설치해보았는데 잘 돌아가더군요. 이번에는 NetBSD에 설치해보기로 했는데 왠만하면 source 컴파일해서 설치하지 말기 바랍니다. 디스크 사용량이 너무 많고 시간이 오래 걸립니다.(거짓말 조금 더해서 하루 정도)

꼭 필요한 패키지는 다음과 같습니다.
x11/qt4-libs, x11/qt4-tools

x11/qt4-docs 도 유용하니 설치해도 좋구, x11/qt4는 이 세가지의 meta-package입니다. 추가적으로 x11/qt4-psql 도 존재하네요.

netbsd ftp의 NetBSD-3.1/i386/All 에 보니 패키지가 다음 처럼 되어 있습니다.

-rw-rw-r-- 1 1115 netbsd 2927 Jun 20 08:52 qt4-4.2.3.tgz
-rw-rw-r-- 1 1115 netbsd 19814564 Jun 19 05:02 qt4-docs-4.2.3.tgz
-rw-rw-r-- 1 1115 netbsd 116137867 Jun 18 20:11 qt4-libs-4.2.3nb1.tgz
-rw-rw-r-- 1 1115 netbsd 435832 Jun 19 04:58 qt4-psql-4.2.3.tgz
-rw-rw-r-- 1 1115 netbsd 47654710 Jun 18 22:04 qt4-tools-4.2.3.tgz

저 엄청난 크기를 보세요. openoffice를 넘어버리는 크기에 놀랐습니다. 참고로 qt4-libs source 컴파일시에 필요한 공간을 보면,

netbsd: {6} df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/wd0a 4.8G 4.4G 145M 96% /
kernfs 1.0K 1.0K 0B 100% /kern

/usr/pkgsrc/x11/qt4-libs/work 삭제 후...

netbsd: {7} df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/wd0a 4.8G 2.8G 1.7G 61% /
kernfs 1.0K 1.0K 0B 100% /kern

library만 컴파일하는데 1.6 GB 정도 필요합니다. 그리고 전 설치시에 다음과 같은 에러가 나더군요.

.obj/release-shared/.libs/qabstractpagesetupdialog.o: could not read symbols: Memory exhausted
gmake: *** [../../lib/../../lib/libQtGui.la] Error 1
*** Error code 2

sysctl 로 사용자 limit를 수정해서 하면 될것 같은데 결국은 해결을 못해서 포기했습니다. 이때 부터 바이너리로 설치 시작...

qt4(4.2.3) 설치 요약
--------------------
qt4-libs: 약 500MB
qt4-tools: 약 165MB
qt4-docs: 약 53MB

설치는 /usr/pkg/qt4/{bin, lib, include, doc. ,,,} 로 됩니다.
PATH, LD_LIBRARY_PATH 환경 변수를 설정해 줘야겠네요.

간단한 build test
-----------------
hello.cpp

#include "QApplication"
#include "QLabel"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel *label = new QLabel("Hello, Qt!");
label->show();
return app.exec();
}

우선 컴파일전에 저는 환경변수를 다음처럼 설정했습니다.
setenv QTDIR /usr/pkg/qt4setenv LD_LIBRARY_PATH /usr/lib:/usr/X11R6/lib:/usr/pkg/lib:/usr/pkg/qt4/lib

QTDIR도 설정을 해야 되더군요.

netbsd: {27} qmake -project
netbsd: {28} qmake hello.pro
netbsd: {29} make
netbsd: {30} ldd hello
netbsd: {31} ldd hello
hello:
-lz.0 => /usr/lib/libz.so.0
-lm.0 => /usr/lib/libm387.so.0
-lm.0 => /usr/lib/libm.so.0
-lpng12.0 => /usr/pkg/lib/libpng12.so.0
-lICE.6 => /usr/X11R6/lib/libICE.so.6
-lSM.6 => /usr/X11R6/lib/libSM.so.6
-lstdc++.5 => /usr/lib/libstdc++.so.5
-lgcc_s.1 => /usr/lib/libgcc_s.so.1
-lpthread.0 => /usr/lib/libpthread.so.0
-lQtCore.4 => /usr/pkg/qt4/lib/libQtCore.so.4
-lX11.6 => /usr/X11R6/lib/libX11.so.6
-lXext.6 => /usr/X11R6/lib/libXext.so.6
-lXi.6 => /usr/X11R6/lib/libXi.so.6
-lXrender.1 => /usr/X11R6/lib/libXrender.so.1
-lXrandr.2 => /usr/X11R6/lib/libXrandr.so.2
-lXfixes.0 => /usr/pkg/lib/libXfixes.so.0
-lXcursor.1 => /usr/X11R6/lib/libXcursor.so.1
-lXinerama.1 => /usr/X11R6/lib/libXinerama.so.1
-lfreetype.6 => /usr/pkg/lib/libfreetype.so.6
-lexpat.4 => /usr/X11R6/lib/libexpat.so.4
-lfreetype.9 => /usr/X11R6/lib/libfreetype.so.9
-lfontconfig.1 => /usr/X11R6/lib/libfontconfig.so.1
-lQtGui.4 => /usr/pkg/qt4/lib/libQtGui.so.4
-lexpat.1 => /usr/pkg/lib/libexpat.
netbsd: {32}

역시 무지 막지하게 DLL을 쓰네요.

PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND
11557 pjy 2 0 3144K 8796K select 0:00 0.00% 0.00% hello

devel/iconv 가 설치되어 있지 않으면 다음과 같은 warning 메시지가 나옵니다.

QIconvCodec::convertToUnicode: using ASCII for conversion, iconv_open failedQIconvCodec::convertFromUnicode: using ASCII for conversion, iconv_open failed


상당히 무겁게 돌아가네요.

소스가 심플한 대신 메모리 잡어먹는 귀신이 되어 버린것 같습니다. 마지막에 조금 실망...

2007년 6월 22일 금요일

Do you enjoy reading a novel?

쉬어가는 의미로 한번 가볍게 읽어주세요.

흔히 영어를 능숙하게 구사하는 분들을 보면 우리말 역시 세련되게 하는 것을 볼수 있습니다. 영어에서 같은 표현이 나오면 동일한 단어를 피하고 유사한 단어를 사용, 다양한 어휘력을 바탕으로 동일한 것을 재미있고 자연스럽게 이해할수 있도록 말을 하는 것을 볼수 있습니다. 그런데 이른바 프로그래머라고 일컬어지는 사람들(me too^^)은 조금은 외부세계와 단절된 듯한 느낌을 보여줍니다. 아니 어찌보면 직업병이라고나 할까. 이진법에 익숙해서 그런지 아날로그적인 애매모호한 일상 생활에 잘 적응하지를 못하는 것 같습니다. 우리들은 이른바 전공 서적이란걸 보기 위해서 영어를 공부하고 기술적인 것을 적용하기 위해서 컴퓨터관련 서적을 뒤져봅니다. 하지만 가만히 노트북을 접고 생각해보면 기술적이라고 하는 것들이 실은 다른 공학이나 인문학에서 영감을 얻어 현재 적용되고 있는 것을 보면 지금처럼 프로그래밍을 공부하는 것이 문법만 죽으라고 공부했던 영어 공부와 무엇이 다를까 의심해 봅니다. 분명히 우리들은 영어 공부 뿐만 아니라 프로그래밍 공부 역시 잘못하고 있다는 느낌을 강하게 느낍니다. 특히 저로서는...

C를 접할때 어렵게 느껴졌던 포인터. 그런데 그 쓰임새가 정말이지 절실하게 느껴졌던 시기는 임베디드 보드에서 실행될 프로그램을 만들때였습니다. 솔직히 그 전까지만 해도 "포인터 = 데이터 포인터" 로만 생각을 했었는데 이젠 "포인터 = 함수 포인터" 이더라구요. kernel 소스나 오픈소스를 뒤져보면 여지없이 나오는 함수 포인터 때문에 참 난감했었는데...

그러고 보면 우리는 버그 투성이의 프로그램을 만들기 위해서 노력하는 동안 해외에서는 소설처럼 읽어볼수 있는 깔끔한 소스를 만들기 위해서 많이 노력한 흔적이 보입니다. 우리는 rapid development 만을 강조했지 rapid에 따른 엄창난 side effect에 대해서는 아무도 대답하지 않습니다. 그때가서 문제가 생기면 회의하자고 하기 바쁜 세상.

다빈치의 모나리자 그림을 접할때면 어떤 생각이 드십니까? 다들 TV에서 접해서 들었던 오묘한 미소가 떠오르십니까? 얼마전 히스토리 채널에 방영한 것을 보고 상당히 놀라움을 금치 못했던 것은 모나리자를 그릴때 그 어떤 덧칠이 가해진 것이 없다는 것입니다. 우리들의 관점으로는 머리속의 생각을 그 어떠한 디버깅없이 바로 소스 코드로 작성했다는 거죠. 다빈치가 현대에 태어났었더라면 정말 멋진 OS가 만들어지지 않았을까 생각해 봅니다.

결론... 좀 거창하지만 만약 문학 비평가, 영화 비평가와 같이 문학이나 예술계에나 있을 법한 학문이 이젠 우리 분야에도 나타날때가되지 않았나 조심스럽게 짐잠해 봅니다. 소스 비평가(code reviwer) 정도로 용어를 만들어 볼수 있을것 같은데 이젠 소스를 어지럽게 써내려 가기 전에 오픈 소스를 소설이나 아니면 수필처럼 읽을 수 있는 여유로운 마음이 필요하지 않나 생각이 됩니다.

ps) 그런면에서 NetBSD 의 소스는 한편의 epic을 읽는 듯한 느낌이 듭니다. 고대 영국 문학의 epic 이 현대에 와서 반지의 제왕과 같은 소설로 다시 부활한 것과 같이 NetBSD는 AT&T UNIX의 서자(?)로 태어나 OS world에서 절대 군주로 자리잡은 진정한 영웅입니다.

Programs should be written to be read, and, whether they are or not, they need to be read.

2007년 6월 20일 수요일

pkgsrc 설치하기

third party 프로그램을 설치하기 위해서 CF Card에 한번 pkgsrc를 설치해보았습니다.
먼저 /usr/pkgsrc 디렉토리를 root 권한으로 생성한 다음 해당 group에 write권한을 준 다음,

% setenv CVSROOT anoncvs@anoncvs.NetBSD.org:/cvsroot
% setenv CVS_RSH ssh
% cd /usr
% cvs -q checkout -rpkgsrc-2007Q1 -P pkgsrc

설치된 pkgsrc의 크기는 200MB 조금 넘었습니다.
설치전,
% df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/wd0a 1.8G 236M 1.4G 13% /
kernfs 1.0K 1.0K 0B 100% /kern
설치후,
% df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/wd0a 1.8G 543M 1.1G 31% /
kernfs 1.0K 1.0K 0B 100% /kern

그렇다면 걸린 시간은?
무려 20시간 가까이 걸렸습니다. :-(

아무래도 NFS를 쓰는 편이 좋을 듯 싶네요. pkgsrc가 cross compile이 지원되는 날이 빨리 오길 기대하며...

2007년 6월 11일 월요일

SC Card mount

요즘 참 멋진 아이디어를 가진 주변장치가 많이 있더군요. SC Card인데 USB로 연결도 되는 제품도 있고, 가격도 저렴하고... 그래서 SC Card를 USB로 마운트를 해보았습니다.

먼저 USB slot에 SC Card를 연결했을때 TS-7200 Console에 다음과 같은 메시지가 나옵니다.

umass0 at uhub0 port 3 configuration 1 interface 0
umass0: Genesys USB Reader, rev 2.00/94.04, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets, 1 lun per target
sd0 at scsibus0 target 0 lun 0: disk removable
sd0: fabricating a geometrysd0: 952 MB, 952 cyl, 64 head, 32 sec, 512 bytes/sect x 1950720 sectors

이와 같은 메시지가 나온다는 것은 제대로 연결되었다는 것이니깐 이젠 마운트하는 것만 남았네요. 먼저 disklabel 명령어로 어떻게 구성되었나 알아봅니다.

# disklabel sd0
# /dev/rsd0c:
type: SCSI
disk: mydisk
label: fictitious-MBR
flags:
bytes/sector: 512
sectors/track: 32
tracks/cylinder: 64
sectors/cylinder: 2048
cylinders: 952
total sectors: 1950720
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0headswitch: 0 # microsecond
strack-to-track seek: 0 # microseconds
drivedata: 0

8 partitions:

# size offset fstype [fsize bsize cpg/sgs]
c: 1950720 0 unused 0 0 # (Cyl. 0 - 952*)
e: 1950591 129 MSDOS # (Cyl. 0*- 952*)
disklabel: boot block size 0
disklabel: super block size 0

sd0e가 MSDOS 파일시스템으로 되어있는 것을 알수 있습니다. 이젠 mount명령으로 마운트 해야죠.

# mount -t msdos /dev/sd0e /mnt

그런데 TS-7200 Console 연결 화면에는 다음과 같은 에러메시지가 나오네요.

sd0(umass0:0:0:0): no door lock
sd0: fabricating a geometry

warning 메시지인가 봅니다. 쓰는데는 아무런 문제가 없네요. 마지막으로 unmount하고 USB slot에서 빼면 Console 연결화면에 다음과 같이 나옵니다.

umass0: at uhub0 port 3 (addr 2) disconnected
sd0 detached
scsibus0 detached
umass0 detached

뭐 별거 아니네요. CF Card대신 USB 메모리를 쓴다면 이런식으로 하면 될거 같네요. 속도 비교를 하자면? 둘다 느리긴 마찬가지입니다 :-(

2007년 6월 7일 목요일

button.c 분석

최종 소스는 ftp://ftp.embeddedarm.com/ts-arm-linux-cd/samples/ 에 위치합니다.
button.c는 입력을 받아 보드에 있는 2개의 led에 점멸을 표시합니다. 여기서는 단순히 LED 점멸만 하는 즉, 쓰기 기능을 하는 것으로 하겠습니다.
TS-7200 Hardware Manual(ts-7200-manual-rev2.2.pdf) 의 7.1 Status LEDs를 보면 Red와 Green 두가지의 LED가 board에 존재하는 것을 알수 있습니다. 사실 EP9302 CPU가 두개의 LED를 지원한다고 보는게 맞겠죠. 메모리위치는 0x8080_0020입니다. 소스코드를 살펴보기전에 다시 한번 GPIO에 대해서 개략적으로 살펴보죠. EP9301 User's Guide 의 Chapter 21에 GPIO 대해서 상세히 나옵니다. Instruction의 내용만 훓어보면 EP9302는 7개의 GPIO port를 지원합니다. 각 port는 동일하게 DR, DDR이 존재하고 interrupt 처리와 같은 기능을 위한 resister도 존재하는데 이기능을 지원하는 port를 EGPIO(Enhaunced GPIO) 라고 합니다. port는 A, B, C, D, E, F, G, H가 존재하고 EGPIO에 해당하는 것은 port A, port B, port F입니다. EP9302는 32bit이기 때문에 register크기도 모두 32bit이지만 실질적으로 사용하는 크기는 다음과 같습니다.
- port A: 8bits
- port B: 8bits
- port C: 1bit
- port E: 2bits
- port F: 3bits
- port G: 2bits
- port F: 4bits

우리가 지금부터 하고자하는 것은 port E에 해당합니다. 2bit가 유효한데 각각 Red, Green LED를 의미합니다. 문서에는 RDLED, GRLED라고 되어있네요. jp.c 와는 다르게 여기에서는 LED를 켜고 끄기 위해서는 쓰기 작업을 해야합니다. 따라서 DR 뿐만 아니라 DDR에 대해서도 작업을 수행해야 합니다. 쓰기 작업은 Read Modify Write (RMW) 방식으로 한다고 했는데 여기서는 Write 만 하고 확인은 직접 board의 LED를 보면서 확인할수 있습니다.

번지 번호 하나 외우고 들어가죠. 0x8084_0000 번지. 이 번지에서 부터 차례대로 GPIO의 resister가 매핑되어 있습니다. EP9301 User's Guide 에는 각 port 의 번지가 나와있는데 TS7200 Hardware 매뉴얼에는 해당 기능에 대한 이름을 열거해 두어서 훨씬 보기 편합니다. 우리의 관심사인 port E의 DR, DDR의 번지는 각각 0x8084_0020, 0x8084_0024 번지에 위치합니다. DR과 DDR의 각 비트위치는 서로 일치합니다. 즉, 0번째 bit가 RDLED의 값과 읽기/쓰기 모드를 나타내고 1번째 bit는 GRLED의 값과 읽기/쓰기 모드를 의미합니다. 지금까지 장황하게 설명했으니 실제 소스를 들여다 보죠.

line 17:
volatile unsigned int *PEDR, *PEDDR, *PBDR, *PBDDR, *GPIOBDB;
주요변수에 대해서 volatile 키워드를 사용했습니다. 그전에는 쓸 기회가 없었는데(사실 뭔지도 몰랐음^^) 이럴때 필요 하더군요. 간단히 말하자면 기계어로 컴파일 될때 최적화에 따른 부작용을 없애자는 거죠. 이 키워드를 쓰면 해당 변수가 들어간 코드에 대해서 컴파일러가 최적화 작업을 수행하지 않습니다. 따라서 소스 레벨에서는 문제 없다가 실행시에 문제가 발생하는 것을 사전에 막아줍니다. 여기서는 unsigned int *로 선언을 했습니다. 여기서는 PEDR, PEDDR만 쓸 예정인데 unsigned char *로 해도 사실은 무방합니다.

line 23:
start = mmap(0, getpagesize(), PROT_READPROT_WRITE, MAP_SHARED, fd, 0x80840000);
마지막 파라미터가 많이 보던 값이죠. GPIO에 접근할때는 이 번지로~~

line 26, line 27:
PEDR = (unsigned int *)(start + 0x20); // port e data
PEDDR = (unsigned int *)(start + 0x24); // port e direction register
start를 unsigned char * 로 선언해 둔 이유를 알겠죠. base 번지로 부터의 상대 주소에 접근할 때 요런식으로 많이 씁니다. 소스코드 보기에도 좋구요. 깔끔하잖아요. PEDR, PEDDR을 unsigned int *로 선언했으니 형변환하는 거 잊지말구요.

line 31:
*PEDDR = 0xff; // all output (just 2 bits)
가장 핵심적인 내용인데 LED에 대해서 쓰기 모드로 지정하겠다는 거죠. 나중에 DR에 값을 쓰면 그 값이 써지게 되어서 결과적으로 LED가 점멸하게 되는 것을 알수 있습니다.

line 35, 36, 37:
while (state & 0x01) { // wait until button goes low
state = *PBDR; // remember bit 0 is pulled up with 4.7k ohm
}
요기서는 위의 코드를 그냥 주석처리하세요. input을 기다리는 내용인데 하드웨어 꾸미기 귀찮아서...

line 42, 44:
*PEDR = 0xff;
*PEDR = 0x00;
위의 코드에서 DDR를 write 모드로 변경했기 때문에 DR에 값을 쓰면 그 결과가 바로 눈으로 나옵니다. 42번 라인을 정확하게 한다면 *PEDR = 0x03; 으로 하는게 맞을거 같은데 사실 32bit의 DR 내용중에서 하위 2bit를 제외하고는 사용하지 않는 내용이니 큰 문제가 되지 않습니다. for() 문과 중간에 sleep()을 주어서 반복하게 되니 차례대로 꺼졌다 켜졌다를 반복하는 것을 눈으로 볼수 있습니다. 간단하죠.

그렇다면 NetBSD 에서는 어떻게 확인할까요?
불행히도 빠져 있네요. 하지만 /usr/src/sys/arch/evbarm/tsarm/tspld.c 에 추가해서 sysctl에 표시되게 하는 방법으로 한다면 일관적이고 사용자 입장에서 편할것 같습니다. Jesse Off 가 별로 필요없을 거 같아 추가를 안했을도 있겠네요. 눈으로 보이는데 굳이 프로그램으로 확인할 필요도 없을 거 같구 굳이 그걸 프로그램에서 알 필요도 없지 않을까요.

알고 보면 상당히 간단합니다. 근데 키패드와 Text LCD는 조금 복잡하네요. scan 기법을 쓰다보니 하드웨어적인 사항도 잘 알아야 되고... 다음엔 이것에 대해서 한번 적어 볼까합니다.

jp.c 분석

최종 소스는 ftp://ftp.embeddedarm.com/ts-arm-linux-cd/samples/ 에 위치합니다.

jp.c는 보드의 좌측 하단에 위치한 6개의 점퍼 상태를 읽는 기능을 합니다.
TS-7200 Hardware Manual(ts-7200-manual-rev2.2.pdf) 의 7.2 Jumpers를 보면 각 점퍼에 대한 memory map 정보가 나옵니다. 그런데 JP1에 대한 map 정보는 없습니다.(이상하죠?) JP2~JP5는 0x1080_0000 에 위치하고 JP6는 0x2280_0000 에 위치합니다. 각 데이터는 1bit에 해당을 하네요. 참고로 DR, DDR이란 말이 나오는데 DR(Data Register)는 말그대로 Data가 위치하는 resister이고 DDR(Data Direction Resister)는 읽기/쓰기는 결정하는 resister입니다. 제가 처음 접했을때 resister는 CPU내에 위치한 resister만 생각했는데 여기서는 resister란 용어를 이렇게도 쓰더군요. 결론은 여기서는 DR만 잘 읽어서 처리하면 끝입니다.

8, 9 line:
#define TSSTATUS 0x10800000
#define TSJP6 0x22800000
이렇게 정의를 해두었습니다. 다른 소스도 마찬가지이겠지만 resister의 번지는 다 이런식으로 정의하고 시작합니다.

20 line:
int fd = open("/dev/mem", O_RDWRO_SYNC);
O_SYNC flag는 앞선 글에서 언급한바와 같이 cash에 따른 부작용을 없애기 위해 필요하고 O_RDWR는 read/write 모드로 파일을 open 하겠다는 뜻이겠죠. 굳이 여기서는 write 모드로 열 필요는 없습니다.

40, 41, 42 line:
page = TSSTATUS & 0xfffff000;
start = mmap(0, getpagesize(), PROT_READPROT_WRITE, MAP_SHARED, fd, page);

사실 여기서는 단순하게 다음처럼 하는것이 더 보기 좋을 것 같네요.
start = mmap(0, getpagesize(), PROT_READPROT_WRITE, MAP_SHARED, fd, TSSTATUS);
여기서 한가지 중요한 것은 우리가 bit단위의 data를 read할 예정이므로 start는 unsigned char* 로 선언되어야 한다는 것입니다. 즉, 읽고자 하는 데이터의 길이를 잘 판단해서 선언해야하는 것이죠. 여기서는 read만 하기 때문에 크게 문제가 되질 않지만 write를 할때에는 자칫 큰 문제가 생길수가 있습니다.

43 line:
dat = (unsigned char *)(start + (TSSTATUS & 0xfff));
이것 역시 다음처럼 하는게 더 보기 좋습니다.
dat = start;

이후 소스는 & 연산자를 이용해서 해당 비트를 읽어서 표시하는 것이니깐 그리 어렵지 않게 이해가 될겁니다.

컴파일해서 TS7200 보드에 실행해보면 점퍼가 꽂아져 있는 곳에는 ON이라는 결과가 나올겁니다. 무지 간단하죠.
그렇다면 NetBSD에서는 어떻게 확인할까요?
sysctl 명령으로 알수 있습니다~ 다음 처럼요.
% sysctl -a
...
hw.tspld.jp1 = 0
hw.tspld.jp2 = 1
hw.tspld.jp3 = 1
hw.tspld.jp4 = 0
hw.tspld.jp5 = 0
hw.tspld.jp6 = 0
...

여기서는 jp1의 상태를 알수가 있네요^^ 소스를 PC의 /usr/src에 받아두었다면 /usr/src/sys/arch/evbarm/tsarm/tspld.c 에 점퍼설정에 대한 내용이 있습니다. linux의 jp.c에 비해서 조금 복잡해 보일지도 모르지만 사용하는 입장에서는 너무나 편리합니다.

accessing peripherals basics in ARM

ARM 프로세스는 주변장치에 접근하기 위해서는 memory mapped I/O 방식을 사용합니다.
x86계열과는 다르게 별도로 instruction이 존재하는 것이 아니라 주변 장치를 위해 필요한 모든 정보(register ...)들이 모두 메모리에 위치하게 됩니다. 이때 물리적 메모리(physical memory)를 논리적 메모리(logical memory)로 매핑해주는 MMU(Memory Management Unit) 의 기능이 OS가 부팅될때 활성화되므로 단지 우리는 해당하는 register가 메모리 어느 번지에 위치하는지 테이블만 보고 해당 작업을 해주면 끝입니다. 사실 Linux Driver를 만든다는 것이 따지고 보면 이런 작업을 좀더 쉽게 함수로 제공해 주는 것 정도라고 봐야겠죠. 하지만 모든 일이 그렇듯이 먼저 이런 일을 해 준 사람에게 고마워해야 할겁니다.
ARM에서는 주변장치라는 말 대신 GPIO(General Purpose Input/Output ) pin 이라는 말을 많이 합니다. 주변장치에 접근하는 하나의 방식이지만 현재는 거의 모든 주변장치에 대해서 GPIO 방식을 이용하는 것으로 보입니다. 하드웨어적으로 하나의 pin으로 존재하는 것에 대해서 GPIO에서는 여러가지 방식으로 접근을 합니다. 가장 기본적인 것이 해당 pin에서 데이터를 읽을 것인가 쓸 것인가(Read/Write)를 결정하는 register가 존재하고, 읽고 쓰는 실제 데이터가 위치하는 register가 존재합니다. 쓰기 작업은 Read Modify Write (RMW) 방식으로 차례대로 진행되는 것이 대부분입니다. 즉, 출력용 주변 장치는 RMW 방식으로 접근하면 되는 것이죠. 그에 비해서 읽기 작업은 Read만 하면 되니 상대적으로 쉽습니다.
실제적으로 프로그래밍을 할때 주변장치에 접근하는 방식은 x86과는 사뭇 다릅니다. 앞에서 언급한바와 같이 별도의 instruction이 존재하는 것이 아니기 때문에 처음 접할때는 상당히 당혹스럽습니다. linux에서는 기본적으로 user level에서 접근할수 있는 방식은 /dev/mem을 직접 접근하는 방식입니다. 이 파일을 mmap() 함수를 이용해서 접근하는 방식이죠. 이후 작업은 대개 비트 연산과 같은 저레벨의 연산 작업을 수행하는 것이 전부입니다. 여기서 주의해야 할 사항은 다음과 같습니다.
- /dev/mem 을 열때 O_SYNC flag 사용할것(cash 기능을 없앱니다.)
- 주요 변수에 volatile 키워드를 사용합니다. 이 역시 cash 기능에 따른 부작용을 없애게 됩니다.
주변장치에 접근하는 방식을 이해하는 것은 소스 파일을 보는 것 만큼 쉬운 방법이 없을 겁니다. ftp://ftp.embeddedarm.com/ts-arm-linux-cd/samples/ 에 있는 파일들이 모두 주변 장치에 접근하는 소스 파일들입니다. 가장 쉬운 것이 jp.c 로 단지 Read 기능 만으로 점퍼의 상태를 알수 있습니다. button.c는 소스 중간에 위치한 while() 문만 주석처리하면 led 점멸을 볼 수 있습니다. 즉, Write 기능을 확인할수 있죠. 이 두개파일만 컴퓨터 구조론 공부할때 배운 내용과 잘 접목시켜서 원리를 이해한다면 x86에서는 느껴보지 못한 희열(?)을 느낄수 있을겁니다. RISC 라는 말이 나온것도 같은 맥락으로 생각하시면 되겠죠. 굳이 주변장치를 접근하는데 instruction을 이용할 필요는 없는 셈이죠. 나머지 소스파일도 잘 봐두면 도움이 됩니다. 요것들이 NetBSD에서는 Driver로 지원을 하거든요~~
여기까지 이해를 했으면 이제는 http://www.embeddedarm.com/downloads/Components/EP9301_User_Guide.pdf 의 EP9301 User's Guide(EP9032 User's Guide는 cirrus 측에서 제공하고 있지 않습니다.) 와 http://www.embeddedarm.com/Manuals/ts-7200-manual-rev2.2.pdf 의 TS-7200 Hardware 메뉴얼을 잘 읽어보는 일만 남았습니다. 두 문서에서 메모리맵에 대한 정보를 잘 비교하면 TS-7200에서 어떤 기능을 구현하고 있는지에 대해서 알수 있습니다.
- EP9301 User's Guide: 2.3.6 Internal Register Map
- TS-7200 Hardware Manual: appendix B Memory and Resister Map
Reference) http://www.simtec.co.uk/appnotes/AN0014/
ps) 너무 글을 두서없이 일기처럼 쓰다보니 정신이 없네요. 한번 예쁘게 PDF 파일로 한번 정리를 해봐야겠습니다.

2007년 5월 25일 금요일

키패드와 Text LCD를 로그인으로 사용하기

NetBSD의 gallery란에 Jesse Off 씨가 올린 그림인데 이 그림에 혹해서 사게 된 계기가 되기도 했지만 정말 될까 의심이 많이 되었습니다. 결론은? 된다고 보는게 맞다.


그런데 또 다른 그림을 보면 이렇게 쓰더군요.
그 유명한 toaster 기계. 그런데 잘 보면 입력은 키패드가 아닌 키보드를 연결해서 쓰고 있죠.
그래서 다음 그림을 또 다시 보게 되었죠.



해외 주문해서 살때 가이드가 되어준 그림이기도 한데(저거랑 똑같이 샀음^^) USB 키보드를 연결해 둔 것을 알 수 있습니다.
NetBSD의 놀라운 또한가지의 특이한 사실을 알게 되는 순간이었는데 NetBSD Guide 설명에서 글로만 보았던 Console driver의 놀라운 능력인 Virtual console 기능을 살리고 위와 같이 연결해 두면 키패드, 키보드 두 군데에서 입력받은 문자가 LCD에 출력이 됩니다. 로그인 해서 ls 등등의 명령어도 실행할수 있습니다. 전 여기서 쓰러지는 줄 알았습니다. 너무 기특해서...
CF Card에 설치한 NetBSD에 조금 설정 상태를 바꾸어 주어야하는데 전 다음과 같이 했습니다.
/etc/ttys 변경
--------------
ttyE0 "/usr/libexec/getty Pc" vt220 off secure
ttyE1 "/usr/libexec/getty Pc" vt220 off secure
ttyE2 "/usr/libexec/getty Pc" vt220 off secure
를 다음처럼 변경
ttyE0 "/usr/libexec/getty LCD" vt100 on secure
ttyE1 "/usr/libexec/getty LCD" vt100 on secure
ttyE2 "/usr/libexec/getty LCD" vt100 on secure

/etc/gettytab에 추가
--------------------
LCD:\
:ce:ck:np:im=%s/%m (%t)\r\n:

/etc/rc.conf에 추가
-------------------
wscons=YES

# sh /etc/rc.d/wscons;/etc/rc.d/ttys restart 하면 된다고 했는데 TS-7200 보드에서는 안되는거 같더군요. 재부팅하면 됩니다.
부팅 중이건 기동 중이건 상관없이 USB 키보드를 연결하면 다음과 비슷한 메시지가 console 창에 뜰겁니다. 아래는 logitec 무선 키보드/마우스를 연결한 상황입니다.
uhidev0 at uhub0 port 1 configuration 1 interface 0
uhidev0: Logitech USB Receiver, rev 1.10/38.10, addr 2, iclass 3/1
ukbd0 at uhidev0: 8 modifier keys, 6 key codes
wskbd1 at ukbd0 mux 1
wskbd1: connecting to wsdisplay0
uhidev1 at uhub0 port 1 configuration 1 interface 1
uhidev1: Logitech USB Receiver, rev 1.10/38.10, addr 2, iclass 3/1
uhidev1: 17 report ids
uhid0 at uhidev1 reportid 2: input=6, output=0, feature=0
uhid1 at uhidev1 reportid 3: input=4, output=0, feature=0
uhid2 at uhidev1 reportid 4: input=1, output=0, feature=0
uhid3 at uhidev1 reportid 16: input=6, output=6, feature=0
uhid4 at uhidev1 reportid 17: input=19, output=19, feature=0
ps) Text LCD가 조금만 커도 꽤 쓸만하겠다는 생각이 드네요. 80x24 짜리면 더 없이 좋겠지만... 그리고 저는 LCD에 /dev/ttyE0가 아닌 /dev/ttyE1 이 뜨더군요. 아직 배울게 많은가 봅니다.

Custom kernel 빌드하기

이 부분이 다른 어떤 OS에서도(같은 계열인 FreeBSD, OpenBSD 도 포함) 맛볼수 없는 어찌보면 디자인한 분의 경외심까지 일으키는 부분입니다. 보통 Linux에서 맨 처음 임베디드보드에 개발을 한다고 하면 Target machine인 임베디드보드는 단지 실행환경만 갖춘 컴퓨터이고 Host machine(보통 x86 계열의 PC)에 Cross compiler를 설치해서 소스를 컴파일해서 결과물로 나온 실행파일을 Target machine에 전송하여 실행이 제대로 되는지 확인하는 방법을 이용합니다. 뭐 사실 CF Card에 NetBSD를 설치했으니 compiler가 설치되어 있어서 직접 컴파일도 할수 있습니다. 참 좋은 세상이죠^^ 하지만 kernel build와 같이 많은 시간을 잡아먹는 작업을 Target machine에서 직접한다는 것은 조금은 바보 같은 짓일겁니다. 그런데 Linux에서 Cross compiler 설치하는 작업이 NetBSD에서는 없습니다. 엄밀하게는 존재하겠지만 이것 역시 compile 작업을 통해서 임시로 설치되게 됩니다. 즉, Cross compiler(NetBSD에서는 tool-chain 이라고 합니다.) 역시 컴파일 단계를 거치게 됩니다. 재미있죠. 어쩌면 이것 역시 바보같은 짓 아니냐 할지 모르지만 NetBSD가 얼마나 많은 플랫폼에 포팅이 되어있는지를 안다면 너무나 편리합니다. Linux라고 한다면 Target machine이 서로 다른 CPU를 가진 보드라고 한다면 아마도 Host machine을 각 임베디드 보드 개수만큼 마련해서 Cross compiler를 설치해 두어야 할겁니다. 하지만 NetBSD는 해당 Target machine에 해당하는 tool-chain을 미리컴파일 해두면 그것으로 족합니다. 내용이 너무 장황하게 다른쪽으로 빠지는 것 같아 이만 줄이고 실제 어떻게 진행되는지 출력내용을 가지고 한번 보겠습니다.

저는 편의상 vmware를 이용해서 NetBSD 3.1을 설치해서 Host machine으로 사용하고 있습니다.

1st. tool-chain 만들기
----------------------
netbsd: {91} ./build.sh -m evbarm tools
===> build.sh command: ./build.sh -m evbarm tools
===> build.sh started: Fri May 11 19:23:40 KST 2007
===> No nonexistent/bin/nbmake, needs building.
===> Bootstrapping nbmake
checking for sh... /bin/sh
checking for gcc... cc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for executable suffix...
checking for object suffix... o
checking whether we are using the GNU C compiler... yes
checking whether cc accepts -g... yes
checking how to run the C preprocessor... cc -E
.........
===> Tools built to /usr/src/tooldir.NetBSD-3.1-i386
===> build.sh started: Fri May 11 19:23:40 KST 2007
===> build.sh ended: Fri May 11 19:46:06 KST 2007
===> Summary of results:
build.sh command: ./build.sh -m evbarm tools
build.sh started: Fri May 11 19:23:40 KST 2007
No nonexistent/bin/nbmake, needs building.
Bootstrapping nbmake
MACHINE: evbarm
MACHINE_ARCH: arm
TOOLDIR path: /usr/src/tooldir.NetBSD-3.1-i386
DESTDIR path: /usr/src/destdir.evbarm
RELEASEDIR path: /usr/src/releasedir
Created /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake
makewrapper: /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake-evbarm
Updated /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake-evbarm
Tools built to /usr/src/tooldir.NetBSD-3.1-i386
build.sh started: Fri May 11 19:23:40 KST 2007
build.sh ended: Fri May 11 19:46:06 KST 2007

시작, 끝나는 시간을 보면 알겠지만 조금 시간이 걸립니다. 뭐 이걸 가지고 딴지 건다면 뭐라 할말은 없습니다.

2nd. kernel 설정하기
---------------------
/usr/src/sys/arch/evbarm/conf 에 있는 걸 이용해서 설정 파일 만들기 여기서는 기본적으로 있는 TS7200_INSTALL 이용하겠습니다.

3rd. kernel 빌드
-----------------
netbsd: {92} ./build.sh -u -m evbarm kernel=TS7200_INSTALL
.......
===> Kernels built from TS7200_INSTALL:
/usr/src/sys/arch/evbarm/compile/obj/TS7200_INSTALL/netbsd
===> build.sh started: Fri May 11 20:03:09 KST 2007
===> build.sh ended: Fri May 11 20:11:19 KST 2007
===> Summary of results:
build.sh command: ./build.sh -u -m evbarm kernel=TS7200_INSTALL
build.sh started: Fri May 11 20:03:09 KST 2007
No nonexistent/bin/nbmake, needs building.
Bootstrapping nbmake
MACHINE: evbarm
MACHINE_ARCH: arm
TOOLDIR path: /usr/src/tooldir.NetBSD-3.1-i386
DESTDIR path: /usr/src/destdir.evbarm
RELEASEDIR path: /usr/src/releasedir
Created /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake
makewrapper: /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake-evbarm
Updated /usr/src/tooldir.NetBSD-3.1-i386/bin/nbmake-evbarm
Building kernel without building new tools
Building kernel: TS7200_INSTALL
Build directory: /usr/src/sys/arch/evbarm/compile/obj/TS7200_INSTALL
Kernels built from TS7200_INSTALL:
/usr/src/sys/arch/evbarm/compile/obj/TS7200_INSTALL/netbsd
build.sh started: Fri May 11 20:03:09 KST 2007

tool-chain 빌드시간보다는 적게 걸렸네요^^

4th. 빌드한 kernel 확인하기
-----------------------------
netbsd: {99} pwd
/usr/obj/sys/arch/evbarm/compile/TS7200_INSTALL
netbsd: {100} ls -al net*
-rwxr-xr-x 1 pjy users 6514722 May 11 20:11 netbsd
-rwxr-xr-x 1 pjy users 6514727 May 11 20:11 netbsd-epe0
-rwxr-xr-x 1 pjy users 6002992 May 11 20:11 netbsd-epe0.bin
-rwxr-xr-x 1 pjy users 6514726 May 11 20:11 netbsd-sd0
-rwxr-xr-x 1 pjy users 6002992 May 11 20:11 netbsd-sd0.bin
-rwxr-xr-x 1 pjy users 6514726 May 11 20:11 netbsd-wd0
-rwxr-xr-x 1 pjy users 6002992 May 11 20:11 netbsd-wd0.bin
-rwxr-xr-x 1 pjy users 6002992 May 11 20:11 netbsd.bin

Jesse Off 씨께서 요렇게 다양한 kernel build물이 나오게끔 설정파일을 만들어 두었습니다. 이건 앞에서의 설정 파일만 조금 보더라도 금방 이해가 갈 겁니다. 그런데 아직 .bin으로 끝나는 것과 아닌것과의 차이를 잘 모르겠네요. CF Card Mount 용 이미지는 netbsd-wd0.bin 이고 CF Card로의 NetBSD 설치에 사용되는 이미지는 netbsd.bin 입니다. 원하는 이미지를 이제 tftp 서버에 위치해두고 Redboot를 이용해서 Kernel을 로드하여 기동하면 다음과 비슷한 메시지가 나오게 됩니다.

RedBoot> go
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
The NetBSD Foundation, Inc. All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
The Regents of the University of California. All rights reserved.

NetBSD 3.1 (TS7200_INSTALL) #0: Fri May 11 20:11:11 KST 2007
pjy@netbsd.myhome:/usr/obj/sys/arch/evbarm/compile/TS7200_INSTALL

로그인후 uname 명령으로도 알수 있구요.


마지막으로 한가지 더 이야기하자면 지금까지 언급한 kernel 빌드 단계가 굳이 임베디드를 위한 cross-compile 환경이 아닌 native 환경에서도 동일하다는 사실. 놀랍죠~ NetBSD의 "Clean Design" 이라는 문구가 단지 말이 아닌 실체로 느껴지는 순간이기도 하죠.

부트 메시지

커널이 다르고 설치된 하드웨어가 다르다면 당연히 부트메시지가 다르겠죠. 그래서 각각의 부트메시지를 모두 종합해 보았습니다.

Case: NetBSD를 CF Card에 설치하기 위해 netbsd-TS7200_INSTALL.bin 커널을 로드한 경우
-----------------------------------------------------------------------------------------------
>> TS-BOOTROM, Rev 1.08 - built 10:44:37, May 26 2006
>> Copyright (C) 2006, Technologic Systems
>> TS-7200: Rev E0 CPU, Rev C PLD, 32MB SDRAM

+Ethernet eth0: MAC address 00:d0:69:40:87:e4
IP: 192.168.0.50/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version current-TS_5 - built 11:53:02, Jun 7 2006

Platform: TS-7200 Board (ARM920T) Rev A
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

RAM: 0x00000000-0x02000000, [0x00044f88-0x01fdd000] available
FLASH: 0x60000000 - 0x61000000, 128 blocks of 0x00020000 bytes each.
== Executing boot script in 0.100 seconds - enter ^C to abort
^C
RedBoot> load -v -r -b 0x00200000 -h 192.168.0.251 netbsd-TS7200_INSTALL.bin
Using default protocol (TFTP)
TFTP timed out 1/15
TFTP timed out 2/15
\
Raw file loaded 0x00200000-0x007c1a07, assumed entry at 0x00200000
RedBoot> go
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
The NetBSD Foundation, Inc. All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
The Regents of the University of California. All rights reserved.

pmap_postinit: Allocated 35 static L1 descriptor tables
NetBSD 3.0_STABLE (TS7200_INSTALL) #1: Fri Jul 21 09:59:42 MST 2006
joff@construct:/home/joff/NetBSD-3/obj/home/joff/NetBSD-3/pristine-src/sys/arch/evbarm/compile/TS7200_INSTALL
total memory = 32768 KB
avail memory = 25188 KB
mainbus0 (root)
cpu0 at mainbus0: ARM920T rev 0 (ARM9TDMI core)
cpu0: DC enabled IC enabled WB enabled EABT
cpu0: 16KB/32B 64-way Instruction cache
cpu0: 16KB/32B 64-way write-back-locking-A Data cache
epsoc0 at mainbus0: Cirrus Logic EP93xx SoC rev E0
epsoc0: fclk 200.03 Mhz hclk 100.01 Mhz pclk 50.01 Mhz
ohci0 at epsoc0 addr 0x80020000-0x80020fff intr 56
epclk0 at epsoc0 addr 0x80810000-0x8081008f intr 35
epe0 at epsoc0 addr 0x80010000-0x8001ffff intr 39
epe0: MAC address 00:d0:69:40:87:e4
ukphy0 at epe0 phy 1: Generic IEEE 802.3u media interface
ukphy0: OUI 0x0010a1, model 0x0021, rev. 9
ukphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
epcom0 at epsoc0 addr 0x808c0000-0x808c0fff intr 52
epcom0: console
epcom1 at epsoc0 addr 0x808d0000-0x808d0fff intr 54
ohci0: OHCI version 1.0
usb0 at ohci0: USB revision 1.0
uhub0 at usb0
uhub0: Cirrus Logic OHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub0: 3 ports with 3 removable, self powered
tspld0 at mainbus0: Technologic Systems TS-7200 rev C, features 0x0
tspld0: jumpers 0x3
wdc0 at tspld0
atabus0 at wdc0 channel 0
tslcd0 at tspld0
wsdisplay0 at tslcd0 kbdmux 1
wsmux1: connecting to wsdisplay0
tskp0 at tspld0: 4x4 matrix keypad, polling at 64 hz
wskbd0 at tskp0 mux 1
wskbd0: connecting to wsdisplay0
tssd0 at tspld0: TS-SDCORE SD flash card core
isa0 at tspld0: PC/104 expansion bus
md0: internal 3075 KB image area
wd0 at atabus0 drive 0:
wd0: drive supports 4-sector PIO transfers, LBA addressing
wd0: 1953 MB, 3970 cyl, 16 head, 63 sec, 512 bytes/sect x 4001760 sectors
wd0: drive supports PIO mode 4, DMA mode 2
boot device:
root on md0a dumps on md0b
root file system type: ffs
WARNING: CHECK AND RESET THE DATE!
erase ^?, werase ^W, kill ^U, intr ^C


Case: CF Card 마운트용 커널인 netbsd-wd0.bin-TS7200 를 로드한 경우
--------------------------------------------------------------------------
>> TS-BOOTROM, Rev 1.08 - built 10:44:37, May 26 2006
>> Copyright (C) 2006, Technologic Systems
>> TS-7200: Rev E0 CPU, Rev C PLD, 32MB SDRAM

+Ethernet eth0: MAC address 00:d0:69:40:87:e4
IP: 192.168.0.50/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version current-TS_5 - built 11:53:02, Jun 7 2006

Platform: TS-7200 Board (ARM920T) Rev A
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

RAM: 0x00000000-0x02000000, [0x00044f88-0x01fdd000] available
FLASH: 0x60000000 - 0x61000000, 128 blocks of 0x00020000 bytes each.
== Executing boot script in 0.100 seconds - enter ^C to abort
^C
RedBoot> fconfig -l
Run script at boot: true
Boot script:
.. fis load vmlinux
.. exec -c "console=ttyAM0,115200 root=/dev/mtdblock1"

Boot script timeout (100ms resolution): 1
Use BOOTP for network configuration: false
Gateway IP address: 192.168.0.1
Local IP address: 192.168.0.50
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.0.1
dns_ip: 192.168.0.1
Network hardware address [MAC]: 0x00:0xD0:0x69:0x40:0x87:0xE4
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false
RedBoot> ip_address
IP: 192.168.0.50/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1
RedBoot> load -v -r -b 0x00200000 -h 192.168.0.251 -m tftp netbsd-wd0.bin-TS7200
/
Raw file loaded 0x00200000-0x004c0def, assumed entry at 0x00200000
RedBoot> go
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
The NetBSD Foundation, Inc. All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
The Regents of the University of California. All rights reserved.

pmap_postinit: Allocated 35 static L1 descriptor tables
NetBSD 3.0_STABLE (TS7200) #1: Fri Jul 21 09:59:22 MST 2006
joff@construct:/home/joff/NetBSD-3/obj/home/joff/NetBSD-3/pristine-src/sys/arch/evbarm/compile/TS7200
total memory = 32768 KB
avail memory = 28196 KB
mainbus0 (root)
cpu0 at mainbus0: ARM920T rev 0 (ARM9TDMI core)
cpu0: DC enabled IC enabled WB enabled EABT
cpu0: 16KB/32B 64-way Instruction cache
cpu0: 16KB/32B 64-way write-back-locking-A Data cache
epsoc0 at mainbus0: Cirrus Logic EP93xx SoC rev E0
epsoc0: fclk 200.03 Mhz hclk 100.01 Mhz pclk 50.01 Mhz
ohci0 at epsoc0 addr 0x80020000-0x80020fff intr 56
epclk0 at epsoc0 addr 0x80810000-0x8081008f intr 35
epe0 at epsoc0 addr 0x80010000-0x8001ffff intr 39
epe0: MAC address 00:d0:69:40:87:e4
ukphy0 at epe0 phy 1: Generic IEEE 802.3u media interface
ukphy0: OUI 0x0010a1, model 0x0021, rev. 9
ukphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
epcom0 at epsoc0 addr 0x808c0000-0x808c0fff intr 52
epcom0: console
epcom1 at epsoc0 addr 0x808d0000-0x808d0fff intr 54
ohci0: OHCI version 1.0
usb0 at ohci0: USB revision 1.0
uhub0 at usb0
uhub0: Cirrus Logic OHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub0: 3 ports with 3 removable, self powered
tspld0 at mainbus0: Technologic Systems TS-7200 rev C, features 0x0
tspld0: jumpers 0x3
wdc0 at tspld0
atabus0 at wdc0 channel 0
tslcd0 at tspld0
wsdisplay0 at tslcd0 kbdmux 1
wsmux1: connecting to wsdisplay0
tskp0 at tspld0: 4x4 matrix keypad, polling at 64 hz
wskbd0 at tskp0 mux 1
wskbd0: connecting to wsdisplay0
tssd0 at tspld0: TS-SDCORE SD flash card core
isa0 at tspld0: PC/104 expansion bus
wd0 at atabus0 drive 0:
wd0: drive supports 4-sector PIO transfers, LBA addressing
wd0: 1953 MB, 3970 cyl, 16 head, 63 sec, 512 bytes/sect x 4001760 sectors
wd0: drive supports PIO mode 4, DMA mode 2
boot device:
root on wd0a dumps on wd0b
WARNING: CHECK AND RESET THE DATE!
Sat Jul 22 02:55:44 KST 2006
swapctl: adding /dev/wd0b as swap device at priority 0
Checking for botched superblock upgrades: done.
Starting file system checks:
/dev/rwd0a: file system is clean; not checking
Setting tty flags.
Setting sysctl variables:
Starting network.
Hostname: ts-7200.
IPv6 mode: host
Configuring network interfaces: epe0.
add net default: gateway 192.168.0.1
Adding interface aliases:
Building databases...
Starting syslogd.
Checking for core dump...
savecore: can't find device 365/452205
Jul 22 02:55:53 ts-7200 savecore: can't find device 365/452205
Mounting all filesystems...
Clearing /tmp.
Creating a.out runtime link editor directory cache.
Checking quotas: done.
Setting securelevel: kern.securelevel: 0 -> 1
Starting virecover.
Starting local daemons:.
Updating motd.
Starting sendmail.
Starting inetd.
Starting cron.
Sat Jul 22 02:56:00 KST 2006

NetBSD/evbarm (ts-7200.) (console)

login:

Case: custom 커널을 로드한 경우
----------------------------------
>> TS-BOOTROM, Rev 1.08 - built 10:44:37, May 26 2006
>> Copyright (C) 2006, Technologic Systems
>> TS-7200: Rev E0 CPU, Rev C PLD, 32MB SDRAM

+Ethernet eth0: MAC address 00:d0:69:40:87:e4
IP: 192.168.0.50/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version current-TS_5 - built 11:53:02, Jun 7 2006

Platform: TS-7200 Board (ARM920T) Rev A
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

RAM: 0x00000000-0x02000000, [0x00044f88-0x01fdd000] available
FLASH: 0x60000000 - 0x61000000, 128 blocks of 0x00020000 bytes each.
== Executing boot script in 0.100 seconds - enter ^C to abort
^C
RedBoot> load -v -r -b 0x00200000 -h 192.168.0.251 -m tftp netbsd-wd0.bin

Raw file loaded 0x00200000-0x007b992f, assumed entry at 0x00200000
RedBoot> go
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
The NetBSD Foundation, Inc. All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
The Regents of the University of California. All rights reserved.

NetBSD 3.1 (TS7200_INSTALL) #0: Fri May 11 20:11:11 KST 2007
pjy@netbsd.myhome:/usr/obj/sys/arch/evbarm/compile/TS7200_INSTALL
total memory = 32768 KB
avail memory = 25220 KB
mainbus0 (root)
cpu0 at mainbus0: ARM920T rev 0 (ARM9TDMI core)
cpu0: DC enabled IC enabled WB enabled EABT
cpu0: 16KB/32B 64-way Instruction cache
cpu0: 16KB/32B 64-way write-back-locking-A Data cache
epsoc0 at mainbus0: Cirrus Logic EP93xx SoC rev E0
epsoc0: fclk 200.03 Mhz hclk 100.01 Mhz pclk 50.01 Mhz
ohci0 at epsoc0 addr 0x80020000-0x80020fff intr 56
epclk0 at epsoc0 addr 0x80810000-0x8081008f intr 35
epe0 at epsoc0 addr 0x80010000-0x8001ffff intr 39
epe0: MAC address 00:d0:69:40:87:e4
ukphy0 at epe0 phy 1: Generic IEEE 802.3u media interface
ukphy0: OUI 0x0010a1, model 0x0021, rev. 9
ukphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
epcom0 at epsoc0 addr 0x808c0000-0x808c0fff intr 52
epcom0: console
epcom1 at epsoc0 addr 0x808d0000-0x808d0fff intr 54
ohci0: OHCI version 1.0
usb0 at ohci0: USB revision 1.0
uhub0 at usb0
uhub0: Cirrus Logic OHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub0: 3 ports with 3 removable, self powered
tspld0 at mainbus0: Technologic Systems TS-7200 rev C, features 0x0
tspld0: jumpers 0x3
isa0 at tspld0: PC/104 expansion bus
wdc0 at tspld0
atabus0 at wdc0 channel 0
tslcd0 at tspld0
wsdisplay0 at tslcd0 kbdmux 1
wsmux1: connecting to wsdisplay0
tskp0 at tspld0: 4x4 matrix keypad, polling at 64 hz
wskbd0 at tskp0 mux 1
wskbd0: connecting to wsdisplay0
md0: internal 3075 KB image area
wd0 at atabus0 drive 0:
wd0: drive supports 4-sector PIO transfers, LBA addressing
wd0: 1953 MB, 3970 cyl, 16 head, 63 sec, 512 bytes/sect x 4001760 sectors
wd0: drive supports PIO mode 4, DMA mode 2
boot device:
root on wd0a dumps on wd0b
WARNING: CHECK AND RESET THE DATE!
Sat Jul 22 10:16:13 KST 2006
swapctl: adding /dev/wd0b as swap device at priority 0
Checking for botched superblock upgrades: done.
Starting file system checks:
/dev/rwd0a: file system is clean; not checking
Setting tty flags.
Setting sysctl variables:
Starting network.
Hostname: ts-7200.
IPv6 mode: host
Configuring network interfaces: epe0.
add net default: gateway 192.168.0.1
Adding interface aliases:
Building databases...
wsdisplay0: screen 1 added (std_tslcd, vt100 emulation)
wsdisplay0: screen 2 added (std_tslcd, vt100 emulation)
wsdisplay0: screen 3 added (std_tslcd, vt100 emulation)
wsdisplay0: screen 4 added (std_tslcd, vt100 emulation)
Starting syslogd.
Checking for core dump...
savecore: can't find device 0/0
Jul 22 10:16:22 ts-7200 savecore: can't find device 0/0
Mounting all filesystems...
Clearing /tmp.
Creating a.out runtime link editor directory cache.
Checking quotas: done.
Setting securelevel: kern.securelevel: 0 -> 1
Starting virecover.
Starting local daemons:.
Updating motd.
Starting sendmail.
Starting inetd.
Starting cron.
Sat Jul 22 10:16:31 KST 2006

NetBSD/evbarm (ts-7200.) (console)

login:


ps) 참고로 저는 RTC를 위해서 TS5620을 같이 구입했는데 해당 하드웨어를 TS-7200에 설치하고 부팅하면 다음 메시지가 나옵니다.

>> TS-BOOTROM, Rev 1.08 - built 10:44:37, May 26 2006
>> Copyright (C) 2006, Technologic Systems
>> TS-7200: Rev E0 CPU, Rev C PLD, 32MB SDRAM
>> TS-5620: detected, battery OK, time ( 11:59:54, May 11 2007 )
....
tsrtc0 at tspld0: mc146818 compatible time-of-day clock