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
*************************************************************************/