월요일, 11월 03, 2008

Windows CE에서 Arabic locale 사용하기 (아랍어 build)

아랍어와 같이 문자가 입력됨에 따라 문자들이 오른쪽에서 왼쪽으로 layout되면서, 인근 문자와 합쳐져서 새로운 문자가 생겨지는 형태의 경우, 단순히 platform settings에서 locale 선택, default language 선택, 그리고 catalog에서 font 선택, keyboard layout 선택만으로는 적절한 locale resource와 input language가 반영되게 할 수 없다.
이런 경우 "Unicode processor for complex scripts" catalog item이 포함되어야 한다.

또 아랍어의 경우 localized resource file이 있지 않다. 즉 common/oak/files/intltrns에는 아랍(사우디아라비아)의 LCID인 0401의 folder가 존재하지 않는다. 예를 들어 사우디아라비아 아랍어 locale을 사용할 경우 사우디아라비아 아랍어로 locale과 default language를 선택한 후, localize the build를 선택하여도 localized resource file이 없기때문에 makeimg단계에서 error를 발생시키며 (fail되는 것은 아니다) default locale인 English(U.S) resource를 사용하여 build된다.
차라리 localize the build를 선택하지 말고 (이 경우 U.S English UI와 사우디아라비아 아랍어 local funtionality를 갖는 OS image가 생성된다) common/oak/files/intltrns/0401 라는 folder를 만든 후 English(U.S)인 0409 folder에서 common.str을 0401 folder로 copy한다. 그 다음에 0401 folder의 common.str를 다음과 같이 수정한다.

#define LOC_LCID ~"401"
#define LOC_ACP ~"4e8"
#define LOC_HKL_DEFAULT "00000401"

LOC_LCID는 사우디아라비아 아랍어의 LCID인 0x0401, LOC_ACP는 사우디아라비아 아랍어의 default code page인 1256의 hex 값, LOC_HKL_DEFAULT는 아랍어의 keyboard layout handle을 입력하게 된다. 여기서 LOC_HKL_DEFAULT에 입력되는 값이 default input language가 된다. 즉 keyboard 입력이 아랍어로 설정되는 것이다.

이렇게 하면 이 값을 받아서 preload keyboard layout이 registry에 다음과 같이 생성된다.

[HKEY_CURRENT_USER\Keyboard Layout\Preload]
@="00000401"

[HKEY_CURRENT_USER\Keyboard Layout\Preload\1]
@="00000401"

이렇게 만들어진 OS image는 IME가 없어서 사우디아라비아 아랍어와 미국 영어 locale을 함께 선택했다고 해도 아랍어만 입력시킬 수 있고 영문 입력은 불가능하다.
한글과 같은 경우 IME에 의해서 영문입력이 가능하지만 아랍어는 IME가 없어서 위와 같은 상황에서는 영어 입력이 안된다. 이 경우 추가 keyboard layout을 registry에서 따로 추가해 줘야 한다.

여기서 위의 registry를 좀더 설명하자면
[HKEY_CURRENT_USER\Keyboard Layout\Preload]는 default preload keyboard layout을 나타내고 [HKEY_CURRENT_USER\Keyboard Layout\Preload\]은 preload keyboard layout을 나타낸다. 이 중 Preload value 1 즉 [HKEY_CURRENT_USER\Keyboard Layout\Preload\1]은 역시 default preload keyboard layout으로 [HKEY_CURRENT_USER\Keyboard Layout\Preload]와 같은 값을 가져야 한다.

영어 입력을 가능하게 하려면 영어 keyboard layout을 preload해야 하며 다음과 같이 registry를 추가해 줘야한다.

[HKEY_CURRENT_USER\Keyboard Layout\Preload]
@="00000401"

[HKEY_CURRENT_USER\Keyboard Layout\Preload\1]
@="00000401"

[HKEY_CURRENT_USER\Keyboard Layout\Preload\2]
@="00000409"

이렇게 하면 booting 직후는 아랍어 입력상태로 있다가 ALT + Shift로 input language를 전환하면 영문 입력상태로 전환된다.
만일 영문입력을 기존으로 하고 아랍어 입력은 필요시마다 전환해서 사용하려면 다음과 같이 하면 될 것이다.

[HKEY_CURRENT_USER\Keyboard Layout\Preload]
@="00000409"

[HKEY_CURRENT_USER\Keyboard Layout\Preload\1]
@="00000409"

[HKEY_CURRENT_USER\Keyboard Layout\Preload\2]
@="00000401"

또 아랍어에서 하듯이 오른쪽에서 왼쪽방향으로 입력하려면 Ctrl + 왼쪽 Shift, 원래대로 왼쪽에서 오른쪽으로 입력하려면 Ctrl + 오른쪽 Shift를 사용하면 된다.

금요일, 10월 10, 2008

Makefile에서 :: (double colon, two consecutive colon) 은?

wince에서 makefile을 보면 target과 그것의 dependency를 지정하는 : 는 알겠지만 빈번히 등장하는 ::은 무엇인가?

이것은 두개이상의 description block을 사용하여 target을 update할 때 사용한다.target이 하나 description block에서 어떤 dependency와 command가 정의되어 있고, 다음에 또 다른 description block에서 이전과는 다른 dependency와 command가 정의될 경우 :: 가 쓰인다.

이럴경우 update된 dependent가 어떤거냐에 따라 처리하는 description block이 달라진다.모든 description block이 처리될 수도 있고, 일부 description block이 처리될 수도 있고, 모든 description block이 처리되지 않을 수도 있다. 즉 마치 서로 완전히 다른 target을 처리하는 것과 같이 행동하므로 별개의 description block이라고 볼 수 있다.

target.lib :: one.asm two.asm three.asm
ML one.asm two.asm three.asm
LIB target -+one.obj -+two.obj -+three.obj;

target.lib :: four.c five.c
CL /c four.c five.c
LIB target -+four.obj -+five.obj;

이 경우 asm file이 update되었을 경우 첫번째 description block이 수행되고 c file이 update되면 두번째 description block이 수행된다. asm file과 c file이 모두 update 되었다면 두 description block이 모두 수행되고, 아무것도 update되지 않았다면 어떤 description block도 수행되지 않는다.

이것은 주로 target을 update할때 사용되는데 dependent의 종류에 따라서 target을 update하기 위한 command의 종류가 다른 경우 사용한다.

Touch sound를 바꾸기

wince에 기본으로 들어 있는 touch sound는 틱틱 거리는 소리로 듣기에 별로 좋은소리는 아닌것 같다.
이 소리의 수정은 다음 directory에서
WINCE600\PUBLIC\COMMON\OAK\DRIVERS\WAVEUI
waveui.rc와 원하는 wav file을 이 directory에 추가시켜 줌에 의해서 가능하다.

원하는 file이 mysound.wav일 경우 이것을 이 directory에 copy해 두고
waveui.rc를 열어 가장 마지막 부분에서 다음과 같이 수정한다.
ID_WAVE_KEYLOUD WAVE keyloud.wav
ID_WAVE_KEYSOFT WAVE keysoft.wav
ID_WAVE_TCHLOUD WAVE mysound.wav
ID_WAVE_TCHSOFT WAVE mysound.wav

그리고 build하면 waveui.lib이 생성된다.
결과물이 lib 이므로 이대로는 OS에 반영이 안된다.

makefile들을 추적하면
waveapi:: $(WAVEAPI_COMPONENTS)
@set TARGETNAME=$@
@set RELEASETYPE=OAK
@set DLLENTRY=_DllMainCRTStartup
@set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_OAKLIB)\audevman.lib
@set TARGETLIBS=%%TARGETLIBS%% $(SG_INPUT_LIB)\wapistub.lib
@set SOURCELIBS=%%SOURCELIBS%% $(SG_INPUT_LIB)\waveui.lib
@set TARGETLIBS=%%TARGETLIBS%% $(SG_INPUT_LIB)\0409\waveapi.res
@set TARGETTYPE=DYNLINK
@set DEFFILE=$(SG_INPUT_LIB)\$@.def
$(MAKECMD) /NOLOGO $@.dll

즉 최종결과물이 waveapi.dll이라는 소리.
다음과 같은 순서로 build하면 된다.
  1. WINCE600\PUBLIC\COMMON\OAK\DRIVERS\WAVEUI 로 이동
  2. build -cp
  3. sysgen -p common waveapi
  4. makeimg

Wince 소리 조절 관련 (volume control panel 설정)

다음 값을 통해서 설정 가능하다.

[HKEY_CURRENT_USER\ControlPanel\Volume]
"Key"=dword:0 ; Keyclicks: 1=soft, 0x10002=loud
"Screen"=dword:10002 ; ScreenTaps: 1=soft, 0x10002=loud
"Mute"=dword:2 ; 7=Enable all sounds (1=Notifications, 2=Apps, 4=Events.)
"Volume"=dword:FFFFFFFF ; 0=off, 0xFFFFFFFF=maximum


Key는 keyboard key 입력시의 틱틱 소리 나는 것을 이야기 하고 Screen은 touch input시 틱틱 소리 나는 것을 이야기 한다.
Wince 제어판의 볼륨과 소리 설정을 보고 비교하면 알기 쉬울 것이다.

위의 예에서는 keyboard 소리는 아주 안나게 했고 touch 소리는 크게, 응용프로그램 소리만 나게 했고, 볼륨은 최대로 했다.

또 전에 말해던 것 처럼 keyboard hardware가 enable되지 않았다고 다음과 같이 알리면

[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\KEYBD]
"Status"=dword:0


실제 제어판 볼륨과 소리에서 keyboard관련 항목이 사라지는 것을 확인할 수 있다.

목요일, 10월 09, 2008

Touch calibration 화면의 문구 바꾸기 (public common module build추적하기)

Touch calibration의 문구를 내 맘대로 바꾸려면 어떻게 해야 하나?
Touch calibration UI을 수정은 아래 public directory의 calibrui.lib에 의해서 이루어 진다.
WINCE600\PUBLIC\COMMON\OAK\DRIVERS\CALIBRUI
그리고 default는 영어지만 locale을 정해줄 경우 locale에 따라서 다른 resource를 사용하게 되는데, 만일 한국어의 경우 아래의 resource을 사용하게 된다.
WINCE600\PUBLIC\COMMON\OAK\LIB\ARMV4I\RETAIL\0412\calibrui.res

그러나 이 calibrui.lib만 가지고는 아무것도 되지 않는다. 수정내용이 반영되려면 최종 DLL이나 exe와 같은 module이 build되어야 하는데 platform쪽의 module build들은 sources들에 의해서 쉽게 추적되지만, public common쪽의 module build은 sysgen과정에서 여러 makefile과 batch file들의 복잡한 동작에 의해서 이루어 진다.
물론 그냥 sysgen을 처음부터 다시 해 주면 되지만, sysgen을 다시하는 전체 build는 보통 30분 이상의 시간이 소요되므로, 자주 수정을 해야 하는 상황에서는 필요한 부분만을 빨리 build하여 반영하는 방법을 알아두어 작업의 효율을 높아진다.
이 경우 makefile들과 batch file들을 추적해 최종 target은 gwes.dll이 된다는 것을 알게 되었다.

그리고 다음과 같은 순서로 build해야 한다.

WINCE600\PUBLIC\COMMON\OAK\LIB\ARMV4I\RETAIL\0412\calibrui.res 에서 문구 수정
set CURRENT_LANGID=0412
WINCE600\PUBLIC\COMMON\OAK\DRIVERS\CALIBRUI\build -cp
sysgen -p common gwes2
sysgen -p common gwes
makeimg

이것은 나중에 별도의 글에서 다시 소개하겠지만 순전히 sysgen_capture tool과 일반 editor의 find in files 기능으로 주요 makefile류의 file들에서 원하는 문구를 추적해 들어감에 의해서 알아낼 수 있다.

우선 calibrui를 검색하여 winceos.bat에서 다음과 같이 calibrui가 사용된다는 것을 알게 된다.

set GWE2_COMPONENTS=%GWE2_COMPONENTS% tchui calibrui

GWE2_COMPONENTS로 다시 검색하면 makefile에서 gwes2.lib가 GWE2_COMPONENTS에 depend on하다는 것과 gwes2.lib은 GWESLIBS로 정의된다는 것을 알게된다.

gwes2::$(GWE2_COMPONENTS)
gwe1 gwe2 gwe3 gwe4::
@set DEFFILE=
@set DLLENTRY=
@set EXEENTRY=
@set TARGETNAME=$@

@set RELEASETYPE=OAK
@set TARGETLIBS=
@set TARGETTYPE=LIBRARY
$(MAKECMD) /NOLOGO $(SG_OUTPUT_OAKLIB)\$@.lib
@set GWELIBS=%%GWELIBS%% $(SG_OUTPUT_OAKLIB)\$@.lib

그리고 GWESLIBS는 gwes_lib.lib를 build하는데 사용된다.

lib_gwes: ceosutil
@set TARGETTYPE=LIBRARY
@set TARGETNAME=gwes_lib
@set RELEASETYPE=OAK
@set TARGETLIBS=
@set SOURCELIBS=%%GWELIBS%% $(SG_OUTPUT_SDKLIB)\ceosutil.lib
@set SOURCEPDBS=$(SG_INPUT_LIB)\mgdi.pdb
@echo Creating gwes_lib.lib $(MAKECMD) /NOLOGO $(SG_OUTPUT_OAKLIB)\gwes_lib.lib

또한 lib_gwes는 gwes.dll이 depend on하는 target이다.

gwes::$(GWES_REPLACE) $(GWES_REPLACE_COMPONENTS) $(GWES_COMPONENTS) lib_gwes
gwes:: 0409_base_resources gwestubs
@set TARGETTYPE=DYNLINK
@set TARGETNAME=$@
@set RELEASETYPE=OAK
@set DEFFILE=$(SG_OUTPUT_OAKLIB)\$@.def
$(SG_TOKENFILTER) $(SG_INPUT_LIB)\$@.def $(SG_OUTPUT_OAKLIB)
@set SOURCELIBS=
@set TARGETLIBS=$(SG_OUTPUT_SDKLIB)\coredll.lib $(SG_OUTPUT_OAKLIB)\gwes_lib.lib $(SG_OUTPUT_SDKLIB)\gwestubs.lib %GWES_TARGET_RESOURCE% $(MAKECMD) /NOLOGO $(SG_OUTPUT_OAKTGT)\gwes.dll
@set DLLENTRY=_DllMainCRTStartup

즉 gwes를 target으로 sysgen하면 denpency에 의해 우선 gwes_lib.lib이 build된다는 것을 알 수 있다. 그리고 또한 gwes_lib.lib을 build하기 위해서는 gwes2.lib이 미리 만들어져 있어야 하지만 따로 dependency가 정의되어 있지 않기 때문에 gwes2.lib을 만들기 위해 gwes2를 target으로 한 sysgen이 먼저 실행되어야 한다. gwes2 또한 calibrui에 depend on하지만 막상 calibrui target은 어떤 library나 module을 build하기 위한 동작을 하지 않는다. calibrui.lib은 sources에 의해서 따로 build된다.

그리고 이런 방식으로 console에서 부분적으로 build하니깐 locale이 반영되지 않아 무조건 미국 locale로만 나온다. 역시 makefile을 보면 CURRENT_LANID가 정의되어 있지 않으면 무조건 미국 locale인 0409가 할당되는 것을 확인 할 수 있다.
그래서 CURRENT_LANID를 0412로 따로 할당해 주는 작업을 한다.

이렇게 해서 결과적으로 처음 이야기한 것과 같은 build 순서가 나오게 된다.
이것을 batch file로 만들어 놓아 source를 조금씩 수정하면서 신속히 build해 수정내용이 어떻게 반영되는지 확인해 가며 coding할 수 있다.

만일 우리가 처음부터 어떤 dll이나 exe가 필요한지 알고있고 있다면 depend on하는 것은 비교적 쉽게 찾을 수 있다. sysgen_capture tool을 사용하면 된다.
'sysgen_capture -p common gwes'명령을 console창에 내리면 sources.gwes를 생성하는데 여기서 다음 정보를 얻을 수있다.
TARGETLIBS=\
$(_SYSGENSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib \
$(_SYSGENOAKROOT)\lib\$(_CPUINDPATH)\gwes_lib.lib \
$(_SYSGENSDKROOT)\lib\$(_CPUINDPATH)\gwestubs.lib \
$(_SYSGENOAKROOT)\target\$(_CPUINDPATH)\0409\gwes.res


그리고 여기에 나열된 lib들이 sources에 의해서 build되는 것이면 상황이 쉬워지는 거고 그렇지 않고 sysgen과정에 생성되는 것이라면 처음과 같은 방법으로 찾아야한다.
sources에 의해서 만들어지는 아닌지는 일반 editorfind in files기능을 사용해서 전체 sources file중에 gwes_lib등의 lib 이름이 있는지 찾아보면 알수 있다.

쉽지 않다.
wince에서 build가 제일 어렵다.

Touch calibraion화면 문구중에서 keyboard관련 내용 없애기

wince 제품 중에는 실제 keyboard hardware가 없고 keybopard hardware를 연결할 수없는 경우가 많다.
그러나 touch calibration 화면에서는 기본적으로 항상 다음과 같은 keyboard관련 문구가 뜬다.
'취소하려면 키를 누르십시오'
'새 설정을 사용하려면 키를 누르십시오'
'기존 설정을 유지하려면 키를 누르십시오'

하지만 keyboard hardware가 없는 환경에서 이런 문구는 말이 되지 않는다.
그럼 keyboard hardware가 없는 환경에서 상황에 맞는 message가 나오게 하려면 어떻게 해야 할까?

다음 registry 값을 추가함에 의해서 가능하다.
[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\KEYBD]
"Status"=dword:0

이 status는 GetKeyboardStatus() call의 return값중 KBDI_KEYBOARD_ENABLED bit을 나타내게 되어 궁극적으로 keyboard hardware가 enable되지 않았다고 알리게 된다. touch calibration은 이 함수의 return값을 참조하여 출력할 문구를 정하게 된다.

수요일, 10월 01, 2008

한글 IME 상태 창 제거하기

wince booting 후 우측 하단에 보면 한글과 한자가 표시된 IME 상태창이 표시된다.
이것을 안보이게 하기 위해서는 다음의 registry 설정을 한다.

[HKEY_CURRENT_USER\ControlPanel\Korean IME UI\Settings]
"ShowState"=dword:0

수요일, 9월 17, 2008

MS환경에서 file들 합치기. 이어서 연결하기. concatenate files

a.txt, b.txt, c.txt 세개의 file들은 순서대로 연결하여 abc.txt를 만든다고 할때 다음과 같이 한다.

cmd.exe를 실행한다.
다음을 입력한다.
copy /b a.txt+b.txt+c.txt abc.txt

토요일, 8월 23, 2008

Protected Server Libraries 2 - PSL의 구현

이번에는 PSL의 구현과 구조를 좀더 자세히 설명한 글인데 최근 어느 blog에서 발견해서 감동적으로 읽었다. PSL에 대한 오랜 세월의 의문에 종지부를 찍었으니깐. 사실 Building Powerful Platforms with Windows CE에서 PSL관련 내용을 읽었을 때는 무슨 내용인지 잘 알수 없었는데 이 blog의 글을 읽고서 책의 내용을 이해할 수 있었다. 책에서는 결정적으로 PSL 자체가 server process라는 점을 언급하고 있지 않았기 때문이다. 이 blog에 의하면 user 역시 PSL을 작성하여 빠르고 overhead없이 동작하는 API를 작성할 수 있다. 원본은 긴 영문으로 작성되어 있고 역시 나중에 잊어버렸을 때의 나 자신을 위해, 나의 이해를 돕기 위해 충분히 의역을 했다.

소개

windows ce thread는 API를 실행하는 동안에 process간에 이동할 수 있다. 이것은 calling process(client process)의 thread를 called process(server process)에 위치시키는 것이다. 이러한 server process는 "procetected server libraries"라고 불리우고 이것은 DLL들처럼 service들(API set)을 export한다.

PSL들은 자신의 process address space에다 API set들을 생성하고 이 API set이 여러개의 client들에 의해서 동시에 call될 수 있도록 하기 위해서 사용된다. WIN32 API들과 device driver, DirectX interface들을 포함한 모든 Windows CE system API들은 PSL을 사용하여 구현된다. 각 API set은 PSL entry와 1대1로 mapping이 된다.

Windows CE는 PSL을 구현하기 위해서 processor fault condition을 이용하는데 이 processor fault condition 발생시 processor fault handler가 PSL entry point를 call 되게되는 구조다. System에는 32개 PSL entry로 이루어진 PSL table이 있다. 각 PSL entry는 API set에 해당하며, 이중 0~24까지는 이미 할당되어 있어 custom PSL이 사용할 수 없다. 즉 25~31까지의 7개의 API set은 user가 등록할 수 있다는 소리다. PSL이 RegisterAPISet()을 통해 자신의 API set를 등록하면 이때 PSL 자신속에 구현된 모든 API function들의 function pointer들로 구성된 table을 system에 제공함에 의해서 API set이 PSL table상의 특정 entry에 할당된다. psyscall.h에 정의되어 있는 PRIV_IMPLICIT_DECL()과 같은 macro들은 PSL ID와 index를 사용해서 function pointer로 사용되게 될 invalid memory address를 구성하게 된다. 이 PSL ID와 index를 통해서 PSL table상의 어느 PSL에서 그리고 그 PSL의 function table에서 어느 function이 call되어야 하는지 알 수 있다. 실제로 API가 call될때는 이 invalid address로의 call이 시도되고 이때 processor fault가 발생한다. 그러면 processor fault handler는 fault address를 보고 이것이 그냥 invalid address가 아닌 PSL address라는 것을 알게 되고 그 address에서 PSL ID와 function index를 구해내어 그것을 통해 적당한 PSL의 적당한 entry point를 call하게 된다. 이것은 caller에서 API function으로 direct jump를 한것과 같은 효과를 보이는데, 실제로는 client process address space에서 server process address space로의 jump가 일어난 것이다. PSL function이 종료되어 return할 때, OS는 PSL API function을 call한 application을 resume하며 return값도 넘긴다. 이것은 마치 client process에서 function이 수행을 끝내고 return한 것과 같은 효과를 보인다. PSI는 system에서 API가 구현되는 핵심적인 방법이고 API의 실행을 위한 code path가 아주 간소해진다.

PSL의 구성요소들

  1. PSL상의 function들 (entry point들)
  2. Function table (Vtable) - PSL상의 function pointer들의 array. 처음 두개의 entry는 kernel에 의해서 사용되는데, 첫번째 entry는 notification procedure로 thread나 process가 stop되거나 start 될 때, low memory가 발생할 때 kernel이 call한다. kernel이 call할 수 있도록 PSL에서 구현돼 있어야 한다. 두번째 entry는 kernel에 의해서 예약돼 있어 0값이 할당되어야 한다.
  3. Signature table - function table상의 각 function의 argument 갯수와 type을 정의한다. function table과 1대1로 대응되는 entry를 갖는 array이다. FNSIG0~12 macro를 사용하여 argument의 갯수를 정의하고 (0부터 12개 까지의 argument를 갖는 function) , DW, PTR, I64 macro를 사용하여 각각 32bit integer (unsigned long), pointer (void *), 64bit integer (long long)의 argument type을 정의한다. Signature table은 kernel에 의해서 사용되는데 kernel은 이것을 통해서 process address space간의 PSL function call에 대해 argument들을 정열한다.
  4. API를 call하는 client application과 link되는 library - 이 lib에는 invalid memory address로의 참조 code가 구현되어 있고 이것이 processor fault를 발생시켜 PSL이 실행되도록 한다. 이 code는 header file에서 inline function으로 구현될 수 있다. Custom API를 추가하려면 역시 user가 구현해 주어야 한다.
사용 예

다음은 custom API 추가의 예를 보여준다.

// 1. Functions
// 1.1 Notify function
// kernel에 의해서 사용되는 function table의 첫번째 entry의 구현

VOID
PmAPINotifyProc(DWORD dwEvent, DWORD dwProcessId, DWORD dwThreadId)
{
switch (dwEvent)
{
case DLL_PROCESS_ATTACH:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_PROCESS_ATTACH ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
case DLL_THREAD_ATTACH:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_THREAD_ATTACH ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
case DLL_THREAD_DETACH:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_THREAD_DETACH ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
case DLL_PROCESS_DETACH:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_PROCESS_DETACH ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
case DLL_PROCESS_EXITING:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_PROCESS_EXITING ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
case DLL_SYSTEM_STARTED:
PMLOGMSG(ZONE_INIT,(TEXT("DLL_SYSTEM_STARTED ProcessId %X, ThreadId %X\r\n"), dwProcessId, dwThreadId));
break;
default:
break;
}
}

// 1.2 Real API
// PSL API function implementationEXTERN_C HANDLE WINAPI
PmSetSystemPowerRequirement(LPCTSTR pszName){
HANDLE hRequirement = NULL;
//...
return hRequirement;
}

// 2. API function table
static VOID PmAPINotifyProc(DWORD dwEvent, DWORD dwProcessId, DWORD dwThreadId);
const PFNVOID VTable[] = {
(PFNVOID)PmAPINotifyProc,
(PFNVOID)NULL,
(PFNVOID)PmSetSystemPowerRequirement,};

// 3. Signatures table
#define NUM_APIS (sizeof(VTable) / sizeof(VTable[0]))
const DWORD SigTable[NUM_APIS] = {
FNSIG3(DW, DW, DW), // PmAPINotifyProc
FNSIG0(), // Kernel reserved entry
FNSIG1(PTR), // Signature of PmSetSystemPowerRequirement
};

// 4. Client APIs (defined in header file)
// Client가 link하는 lib의 구현
#define PM_APISET_ID 25 // APISet ID
#define PM_APISET_NAME "CPM" // APISet Name
#define PmSetSystemPowerRequirement_xxx \
PRIV_IMPLICIT_DECL(HANDLE, PM_APISET_ID, 3, (LPCTSTR psz))

__inline HANDLE
SetSystemPowerRequirement(LPCTSTR pszState) {
ASSERT(QueryAPISetID(PM_APISET_NAME) == PM_APISET_ID);
return IsAPIReady(PM_APISET_ID) ? PmSetSystemPowerRequirement_xxx(pszState) : NULL;
}

// 5. Create and register APISet
// PSL에서의 Initialization - API set을 등록하는 부분
hPmAPISet = CreateAPISet(PM_APISET_NAME, NUM_APIS, VTable, SigTable);
if (ghPmAPISet == NULL) {
PMLOGMSG(ZONE_ERROR, (_T("%s: CreateAPISet() failed: %d\r\n"), pszFname, GetLastError()));
return FALSE;
}
if (!RegisterAPISet(ghPmAPISet, PM_APISET_ID)) {
PMLOGMSG(ZONE_ERROR, (_T("%s: RegisterAPISet() failed: %d\r\n"), pszFname, GetLastError()));
CloseHandle(ghPmAPISet);
return FALSE;
}


Code에 대해서 몇가지 부가 설명하자면
PRIV_IMPLICIT_DECL - PSL ID와 function index가 encode된 invalid function pointer 생성
IsAPIReady - API set이 등록되었는지 여부를 나타낸다. 만일 API set가 등록될 때까지 대기해야 한다면 이것을 주기적으로 call하면서 polling했어야 했는데 CE6.0에서는 이 함수가 지원되지 않는다. 대신 CE6.0에서는 WaitForAPIReady를 사용한다. 이것을 API가 등록될 때까지 대기하는 기능을 가지고 있다.
CreateAPISet - API set 생성
RegisterAPISet - API set 등록

영문원본 출처 - http://bhduan.blogspot.com/2006/11/using-protected-server-libraries-psl.html

Protected Server Libraries - 기본 개념

protected server libraries 즉 PSL이란 것. 가끔 wince 관련 기술문서들에서 그것도 아주 아주 가끔 등장하지만 정작 그게 뭔지 제대로 설명하는 글은 거의 찾을 수 없다. 단지 'thread가 process들간을 이동(migrate)한다'는 식의 별로 도움 안되는 짧은 설명들만 있을 뿐이다. 사실 알 필요가 없어서 이기도 하겠지만 그렇다면야 아예 언급을 하지 말던가. 언급은 해 놓고 설명을 안해주는 것은 대체 무슨 심보인가? 그나마 약간이라도 설명하고 있는 책이 있었으니 'Building Powerful Platform with Windows CE'에서다. PSL을 설명하는 부분의 내용을 이해하기 쉽도록 옮겨본다. 밝혀두지만 직역이 아니고 이해 하기 쉽도록 충분히 의역해서 원본과는 상당히 다른 글이 되었있다. 심지어 원본에 없는 부가 설명도 추가했고 원본의 설명이 틀렸다고 생각되는 부분은 내 생각으로 고쳐서 썼다. 원래 이 책은 친절한 책이 못되고 그래서 읽기도 무척 괴롭다.

Slot memory 구조때문에 process들의 memory space가 서로 구분/분리 되어 있는데, 한 process에 의해서 할당된 buffer가 다른 process에 의해서 어떻게 access될 수 있을까? 이것이 가능한 것도 바로 slot구조이기 때문이다. Slot구조에서는 모든 process들이 2GB 공간에서 각자의 서로 다른 공간을 할당 받은 상태이고, kernel은 이 2GB영역을 모두 access할 수 있으므로 kernel에 의한 translation에 의해서 이것이 가능해 진다.

하나의 process가 다른 process에 있는 function을 call한다고 할때 calling process를 client process, called process를 server process라고 하기로 하자.

Client process가 server process의 function을 API로써 call한다면, 그 API를 수행하는 thread는 server process의 context에서 실행 된다. 당연한 말인데 API를 수행하는 thread는 자신이 속한 process memory space에서 동작하는 것이다. 그런데 이것은 process간에 crash를 유발할 수 있다. 왜냐하면 API를 수행하는 server process의 thread는 client process memory space의 API parameter를 가지고 server process의 context에서 작업을 수행해야 하는데, 알다시피 Windows CE slot memory 구조에서는 process간의 memory space는 구분되어 있다.

이것을 해결하기 위한 일반적인 방법은 역시 위에서 언급한 것 처럼 2GB영역을 모두 볼 수 있는 kernel의 개입에 의해서 인데, client process에 의한 API call을 kernel이 trap한 후 API parameter를 server process의 API를 수행하는 thread로 copy하여 넘기고, server process가 API수행을 완료하면, 다시 kernel이 결과를 client process에게 copy해서 넘긴다.
그러나 이 방법에는 overhead가 있는데 client process가 API call을 하려면 server process에서 API function을 수행하는 thread가 있어야 하기 때문이다. thread가 있어야 한다는 것은 이것을 위한 stack과 memory가 있어야 한다는 말인데, resource가 제약된 embedded system에서는 이런 resource 소모는 최소화 되어야 좋다. 이런 overhead를 없애기 위한 것이 바로 Protected Server Libraries다. PSL 자체가 overhead를 없애기 위한 방법이 적용된 server process다. PSL은 API set를 구현하고 이것을 kernel에 등록 시킨다. 그럼 kernel은 그 API function의 signature를 기억해 두었다가, 이전과 같이 client process에서 PSL의 API를 call하면, kernel은 client process에서 발생된 API call을 trap한 후, client process에서 API call을 발생시킨 thread를 PSL의 process space에서 run하도록 만든다. 이렇게 해서 PSL에서는 API call을 수행하기 위해서 thread를 따로 생성해야 하는 overhead를 제거할 수 있다.

Client process의 thread가 PSL로 진입할때, 이 thread는 PSL과 PSL address space로의 access권한을 자동으로 부여받게 되어 PSL 내에 존재하는 다른 thread들 처럼 동작할 수 있다. Thread가 PSL을 떠나게 되면 이 access권한도 제거된다. 모든 Slot내의 매 64Kb memory block 마다 read/write등의 여러가지 access 허가상태가 설정되어 있다. 이 slot내 memory block을 access하여 어떤 동작을 하려 하면, kernel은 그 동작을 하려는 thread가 그 memory block에 대해 올바른 access권한이 있는지 check한다. 그래서 만일 PSL이 아닌 다른 어떤 process내에서 동작중인 thread가 PSL의 memory를 modifiy하는 등의 동작을 하려하면 거부된다.

일요일, 8월 17, 2008

나의 인생 나의 기타

한달전쯤인가..
KBS 2 TV에서 토요 프리미어 극장인가 하는 토요명화 후속 영화 프로그램에서 '나의 인생 나의 기타'라는 영화를 봤다. 원제는 'the guitar'였는데.. 나에게는 매우 뜻 깊은 영화였다.
인터넷 영화평은 지루하다, 별 내용 없다 는 등의 말들이 많았지만, 기타리스트 혹은 뮤지션이 되는게 인생의 꿈이였고 아직도 내 장래 희망은 Rock'n Roll star 라고 이야기 하는 나에게 이 영화는 내가 전기기타에 대해 품고있던 환상을 다시금 일깨워 주었다.
영화 내용은 여자 주인공이 말기 암이란 의사의 진단을 듣고 얼마 안남은 인생에서 하고 싶던것들을 해 보고 살겠다며 고급 아파트를 임대해 마음대로 물건을 사고, 관계를 가지며 살아가게 된다.
그 중에 하나가 기타를 구입하서 배우는 것이다. 어렸을 적의 회상장면에서 턴테이블로 음악을 듣던 장면, 악기가게에 진열된 전기기타를 가지고 싶어하는 장면, 기타를 훔쳐 달아나다가 주인에게 잡혀 혼나는 장면들이 나오고, 여자는 죽기전에 해보고 싶은것들 중 하나로써 기타를 구입한다. 여자는 기타 뿐만 아니라 신용카드를 온갖가지의 것들을 사 들이는데, 어차피 죽을 것이니 지불계획같은 것은 신경쓰지 않는다.
아무튼 그렇게 시간 가는지 모르고 지내다 보니 의사가 선고한 죽어야 될때가 이미 지났는데도 아직 죽지 않고 있다는 것을 깨닫게 된다. 다시 찾아간 병원에서 의사가 말하길 너무 스스로를 많이 바꿔서 암이 환자를 인식하지 못해 사라졌다고 한다. 여자가 하고 싶은 것들을 하며 사는게 너무 큰 일탈 이었고, 이것때문에 사람이 너무 바뀌어 암세포가 '이것은 내가 살던 사람의 몸이 아니네' 하고 사라졌다는 것이다. 하고 싶은것을 하고 산다는 게 임박한 죽음조차 못 알아볼 정도로 나를 완전히 다른사람 처럼 인식되게 한다는 생각을 하니 우리의 인생이란게 참 불쌍하다는 생각이 들었다. 원래 이렇게 살라고 주어진 인생이 아니었을 텐데 우린 뭘 이루겠다고 이렇게 힘겹게 살아가고 있는 것인지...
여자는 암에서 완치 됐지만 신용카드를 너무 막 쓴 탓에 카드 빚 갚느라 기타만 남기고 그간 무분별하게 샀던 물건들을 팔아치웠고, 결국 노숙자 신세가 된다. 공원에서 푼돈이나마 벌기위해 기타를 치다가 어느 밴드에게 그녀의 기타실력이 주목을 받게 되고... 마지막 장면은 우리나라로 치면 홍대 클럽같은 곳에서 그 어느 밴드의 기타리스트로써 음악을 연주하는 장면으로 보여지면서 영화는 끝을 맺는다.
여자는 암을 계기로 자신을 바꿨고 그 댓가로 자신의 모든것도 잃게 된다. 하지만 그러면 어떠한가. 대신 정말 원하던 꿈을 이루게 되는데.
나도 내 오랜 꿈의 한 발자국을 내 딛었다.
나도 드디어 기타를 샀다.
초보자용으로 별로 대단한 제품은 아니다. 인터넷에서 초저가 초보자용 모델을 구입햇다.
제품명을 Dame사의 Saint T250 DBS(M).
기타 스탠드와 연습용 앰프, 기타 tunner등이 포함된 package로 된 상품이다.
취미겠지만 진지하게 해 볼 생각이다.
언니네 이발관이 내게 용기를 준 이후 10년이 넘게 지났다.

월요일, 8월 11, 2008

Windows CE debugging tips

KITL을 사용할 수 없는 상황에서 debugging을 해야 하는 처지에 놓였을 때 예전에 Microsoft blog에서 ninja debugging skill이라고 묘사되었던 글들이 생각났다. 읽은지 2년정도 지난것 같다. 하지만 늘 그렇듯이 하나도 기억 안난다.
그 blog는 아직 남아 있지만 온통 장문의 영어로 된 글들이라 도대체 다시 읽을 엄두가 나지 않았다.
이번에 다시 한번 극기하며 공부하고 나중을 위해서 요점을 이곳에 정리해 두어야 겠다는 생각이 들었다.
사실 내 blog의 애초 주요 목적도 그것이었다.
많은 것을 매일 매일 배워나가지만 어느 하나 지속적으로 오래 사용하지 않으니 금방 잊어버리고, 다시 필요한 일이 생기면 처음 시작하는 마음으로 다시 공부해야 한다. 공부를 막 마쳤을 때 생생하게 이해하고 있는 내용을 쉽게 풀어 기록해 놓으면 다음에 잊어버렸다가 다시 필요해 질때 처음부터 다시 공부해야 하는 수고를 좀 덜지 않을까 하는 생각이 들었다. 생각해 보면 대부분의 쓸모있는 전문 정보들는 거의 영문으로 되어있다. 웹상에 한글 정보들은 대부분 놀고 먹고 즐기는 내용들뿐 정말 필요한 전문적 지식들은 거의 찾아 볼 수가 없다. 한국 인터넷 문화의 부끄러운 단면이라고나 할까?

목요일, 8월 07, 2008

WINCEOEM, _OEMINCPATH, _ISVINCPATH

WINCEOEM이 set이면 _OEMINCPATH가 INCLUDEPATH에 포함된다.
WINCEOEM이 not set이면 _ISVINCPATH가 INCLUDEPATH에 포함된다.

_OEMINCPATH와 _ISVINCPATH의 내용은 sources.cmn에서 정의되어 있고, WINCEOEM의 설정에 따른 INCLUDEPATH의 설정 변화는 makefile.def에서 정의되어 있다.

즉 WINCEOEM=1이면 해당 build는 OEM (original equipment manufacturer)에 의해서 사용된다는 것이고 그렇지 않으면 ISV(independent software vendor)에 의해서 사용된다는 것이다.

보통 _OEMINCPATH는 $(_WINCEROOT)\public\common\oak\inc;$(_WINCEROOT)\public\common\sdk\inc;$(_WINCEROOT)\public\common\ddk\inc;
_ISVINCPATH는 $(_WINCEROOT)\public\common\sdk\inc;
로 정의된다.

딱 보면 알겠지만 _ISVINCPATH는 이미 만들어진 target hardware와 NK.bin, SDK만을 받은 상태에서 application만을 개발하는 사람들을 위한 것이고, _OEMINCPATH는 application뿐만 아니라 driver, OAL, bootloader등의 system level program까지 개발하는 사람들을 위한 것이다.
original equipment manufacturer나 independent software vendor가 각각 그런 사람들을 뜻한다고 볼 수 있다.

화요일, 7월 22, 2008

.dat - 초기 directory 구조 설정

object store 영역의 directory layout를 설정하고, ROM file을 그 diretory layout 상 특정한 곳으로 copy한다. 여기서 ROM file이란 OS image에 포함되는 file을 이야기 하는데 이 file은 object store의 \Windows directory에 위치하게 된다. 이런 file을 \Windows가 아닌 다른 곳에 위치하게 하려면 이 .dat file을 사용해야 한다. 하지만 이것은 어디까지나 \Windows 아래에 있는 file을 다른 위치로 copy만을 할 뿐이지 move하지는 않는다. (이 말은 큰 size의 file에 대해서 적용한다면 object store 영역을 소모시킨다는 이야기로 받아들여 지다.)

root:-Directory("name")
root directory 아래에 name이라는 directory를 만든다.

root:-Permdir("name")
root directory 아래에 name이라는 permanent directory (RemoveDirectory API로 remove될 수 없다)를 만든다.

Directory("\path"):-Directory("name")
\path 위치 아래에 name이라는 subdirectory를 만든다. name 아래에 name2라는 subdirectory를 또 만드려면 이 directive다음에 다음을 입력한다.
Directory("\path\name"):-Directory("name2")
subdirectory의 subdirectory는 계속 위와 같은 방법으로 하면 된다.

Directory("\path"):-File("targetfile", "sourcefile")
sourcefile는 ROM file의 path와 이름을 나타내고, 이 file을 targetfile이라는 이름을 바꿔서 \path 아래로 copy한다.

수요일, 7월 02, 2008

WINCE에서 2개가 넘는 multi channel speaker 출력이 가능할까?

"WINCE에서 2개가 넘는 multi channel speaker가 있을때 각 channel로 서로다른 sound의 동시 출력이 가능할까?"라는 문제 관련하여 나름대로 조사해 보고 내가 알게 된 부분과 궁금한 점을 naver weeg와 wecom에 올렸고, 도움이 되는 답변도 얻었다.

질문
흔히 mobile device에서 사용하는 AC97 codec은 aclink data의 slot3, 4 data를 DA변환하여 LOUT_R, LOUT_L 출력할 수 있도록 해 줍니다. DAC가 보통 2개, 또는 wolfson wm9712의 경우는 auxDAC를 가지고 있어 3개의 DAC가 있고, 이 auxDAC는 costant 값을 설정하여 BEEP소리가 나게 하던가 aclink data의 5에서 11사이의 slot을 할당해 줄 수 있습니다. 그럼 그 slot으로 오는 aclink data가 auxDAC를 거치겠지요.

의문점은 windows ce환경에서
waveform audio의 waveout 함수들로 audio 출력할때 WAVEFORMATEX의 nChannels를 3으로 설정할 수 있느냐? 그렇게 해서 auxDAC를 포함한 3 channel의 speaker에서 서로 다른 소리가 나게 할 수 있는 것인가? 입니다.

PC에서는 multi channel speaker를 연결하도록 여러개의 speaker jack들이 있고 해서, 이런환경에 많이 사용하는 C-media의 AC97 codec을 찾아 봤습니다. 4ch, 혹은 6ch를 지원하는 것들이 있는데...
4ch짜리 AC97 codec은 4개의 DAC를 가지고 있고 실제 LOUT_R, LOUT_L외에 REAR_OUT_R, REAR_OUT_L 출력을 가지고 있습니다. AC97 표준에 따라 아마도 이 rear left, right는 AClink의 slot7, 8의 data를 받을 겁니다. (제품명이 CMI9738)
6ch짜리 AC97 codec은 6개의 DAC를 가지고 있고 실제 LOUT_R, LOUT_L외에 REAR_OUT_R, REAR_OUT_L, CENTER_OUT, LFE_OUT 출력을 가지고 있습니다. AC97 표준에 따라 아마도 이 rear left, right, center, lfe는 AClink의 slot6, 7, 8, 9의 data를 받을 겁니다. (제품명이 CMI9761)

그렇다면 wince환경에서 이 2 channel 초과의 audio를 동시에 여러개의 speaker로 따로따로 다른 소리를 출력할 수 있는 방법이 있습니까?
WAVEFORMATEX의 nChannels를 4나 6으로 설정하면 될까요?
아니면 다른 어떤 방법이 있나요?
wince에서는 안된다면 PC에서는 이렇게 2channel이 넘는 multi channel speaker로 서로 다른 소리가 나가게 하기 위해서 어떻게 하나요?


답글 (wecom)
http://msdn.microsoft.com/en-us/library/aa910386.aspx 에서 볼 수 있듯이 윈도우CE에서 지원하는(혹은 생성할 수 있는 오디오 형식이) 모노나 스테레오 둘중에 하나이기 때문에 2채널 이상을 설정하셔도 의미가 없을 것입니다.제가 아는 한 그렇습니다.참고하시기 바랍니다.

Microsoft Windows Embedded MVP

Youngho Ra(ratharn@naver.com)
www.embeddedce.com

실제 msdn 해당 website에 가면 WAVEOUTCAPS 라는 waveform audio output device의 capability를 정의하는 구조체의 설명이 있는데, 이 구조체의 member인 dwChannels은 1 과 2 만 지원된다고 명시돼있다. 또 dwFormats에서는 지원되는 WAV format을 지정할 수 있는데 이것도 여러가지 sample rate에 mono, stereo만 지원된다고 나와 있다.

답글 (weeg)
WAVEFORMATEXTENSIBLE에 대해서 찾아 보시면 될 듯 합니다.

이 내용을 MSDN에서 확인해 보니
PC환경에서는 WAVEFORMATEXTENSIBLE은 일반적인 PCM format wav가 아닌 경우 추가 정보를 지정하기 위해 사용하는 구조체로, Multichannel & high resolution wav format을 정의할 수 있고 이것을 이용해서 18개나 되는 channel의 speaker까지 동시 출력을 할 수 있도록 되어 있다. 이 WAVEFORMATEXTENSIBLE을 사용해서 정의되는 WAV format은 Directsound에서 사용된다.
그러나 wince 환경에서는 DirectSound를 지원하지 않는다.
Wince의 모든 source file을 search해 본 결과 이 구조체가 정의는 되어 있으나 전혀 사용되지 않는다. 따라서 wince에서는 안 되는 기능이라고 생각된다.

결론적으로 원하는 기능을 위해서는 우선 multi-channel을 지원하는 고급 AC97 codec를 사용하고 window의 waveform audio 함수를 사용하지 않고, 독자적인 driver와 독자적인 application interface를 새로 구현하는 수 밖에 없어 보인다.

월요일, 6월 30, 2008

CFI (Common Flash Interface)

Flash memory에서 읽혀질 수 있는 표준화된 data structure.
CFI를 통해서 system software는 장착된 flash memory의 configuration과 다양한 electrical, timing parameter, 기능들을 알 수 있다. 즉, CFI를 통해서 system은 flash device를 최적으로 interface할 수 있는 방법을 알 수 있다.


출처: ATMEL website http://www.atmel.com/dyn/products/faq_card.asp?faq_id=1745&family_id=624&family_name=Parallel%20Flash

일요일, 6월 29, 2008

29일 새벽 촛불집회


집회에 참가하진 못했지만 그렇다고 속편히 잠도 못자겠다. ohmynews, 한겨레, pressian, 경향의 시시각각 update되는 기사도 읽어보며, 대표적인 집회 internet 중계방송들도 동시에 보고 있다.
사진은 현재 내 컴퓨터 화면을 capture한 것.
화면우측은 ohmynews 기사화면이고 좌측은 중계방송화면들이다. 시계방향으로 우측 상단부터 ohmynews, 한겨레, 진보신당, 민중의 소리.
생각해 보니 87년 오늘이 6.29 선언일이다.

금요일, 6월 27, 2008

2008년 6월16일 영흥도 십리포해변, 소사나무 숲

지난 6월 16일 영흥도 십리포해변에 갔다가 찍은 사진을 한장을 테스트삼아 올려본다.

130년된 국내 유일 소사나무 숲이라고 한다. 구불구불한 나무들이 마치 동화속에서나 나올것 같은 분위기를 만들어 낸다.

목요일, 6월 26, 2008

아버지와의 논쟁

최근 아버님 댁이 이사하시는 것을 계기로 구독신문을 중앙일보에서 경향신문으로 바꿔 보시게 했다. 중앙일보가 얼마나 악의적 편파성을 가지고 있으며 경향신문은 그다지 좌파적이지 않으면서 너무 무미건조할 정도로 공정성을 유지하고 있다고 설득하며...

그러다 이번주 월요일 아버지랑 소주한잔 할 일이 있었는데, 피하고 싶었던 현 촛불집회와 정치 경제적 상황에 대해서 논쟁이 있었다. 경향신문이 좌파적이고 선동적이란 말도 하셨고...
몇 년전부터 나는 아버지와 이런 류의 대화를 의도적으로 피하며 그냥 받아들이는 자세를 보여 왔는데, 내가 그래왔던 이유는 아버지를 결코 논리적으로 설득할 수 없고, 부모를 이기는 것은 무상한 일이며 부모님께 상처만 남길 수 있다는 것을 알기 때문이다.

오늘자 한겨례 신문에서 내 느낌을 잘 표한하는 글을 보게 되었다.
김어준의 그까이꺼 아나토미
삽화에 다음과 같이 쓰여 있다.
"지난 대선 언저리의 기억 한토막. (택시운전)기사는 육두문자를 써가며 빨갱이 정부를 성토했고, 이제 한두달 후면 새 시대가 올 것이라 확신했으며 그 시대를 이끌 지도자는 단연코 이명박 이었다. 나는 한마디 대꾸 하려다 그의 깊은 주름을 보고, 그만 두었다"
그리고 김어준은 이야기 한다. "그러나 장인(혹은 부모)을 개안시키려는 남편의 시도도 무망하다. 그건 그것대로 부모 세대의 존재양식이었기 때문에. 부모를 바꾸려는 모든 시도는, 그것이 논리적이지 않아서가 아니라 그들의 살아온 방식 자체를 부정하란 것으로 여겨지기에, 실패한다"

이 부분까지 읽는데 순간 가슴이 먹먹해 왔다.

수요일, 6월 25, 2008

FSRAMPERCENT

config.bib file에서 사용된다.
이 환경변수의 이름은 File System RAM PERCENT를 나타내려고 했던 것 같다.
RAM 전체크기중에서 file system (object store)에 할당되는 영역의 percentage를 설정하기 위해서 사용된다.
object store의 최소값은 32KB, 최대값은 256MB란다.

다음과 같이 4byte의 값으로 설정하는데

FSRAMPERCENT=0xXXXXXXXX

MSB쪽 byte를 byte3, LSB쪽 byte를 byte0이라고 했을 때
byte0 = 처음 2MB에서 MB당 4kbyte block의 갯수
byte1 = 두번째 2MB에서 MB당 4kbyte block의 갯수
byte2 = 세번째 2MB에서 MB당 4kbyte block의 갯수
byte3 = 나머지 memory에서 MB당 4kbyte block의 갯수
를 나타낸다.

default값이 0x80808080인데 이것은 매 MB당 512KB (4*1024*0x80)이므로 전체 RAM중 50%가 object store에 할당 되었다는 것이다.

FSRAMPERCENT에 의해 RAM상에서 object store으로 할당된 영역의 percent 계산하기
FSRAMPERCENT의 각 byte가 동일한 값을 가질 경우, 전체 RAM에서 매 1MB당 object store에 할당된 percent를 알수 있다.
예를들어 0x20202020이라면 1MB당 128KB를 할당하므로 128KB/1MB = 0.125. 전체 RAM중 12.5%가 object store에 할당 된 거다.
만일 FSRAMPERCENT의 각 byte값이 다르다면 계산이 복잡해 질수도 있겠다.

RAM상에서 object store으로 할당할 영역의 percent값으로 부터 FSRAMPERCENT 구하기
만일 12.5%를 object store에 할당하려면 FSRAMPERCENT의 각 byte를 다음과 같이 구한다.
100:12.5 = 1MB:(4KB*x)
100 * 4KB * x = 12.5 * 1MB
x = (12.5 * 1MB) / (100 * 4KB)
x = 32 = 0x20
즉 각 byte를 0x20으로 하여 FSRAMPERCENT를 0x20202020로 설정한다.

월요일, 6월 23, 2008

WINCEPROJ, WINCETREE, OS project, WINCEPROJ project

WINCEPROJ와 WINCETREE가 비슷하게 사용되는 것 같은데 차이가 무엇일까 조사해 봤다.

WINCEPROJ
Building powerful platforms with windows ce에서의 설명 다음과 같다.

"Project의 scope를 나타낸다. Module이 여러 project에 걸쳐서 사용될 것이라면 COMMON으로 설정되고, 현재의 project에서만 사용될 것이라면 current로 설정한다."

그러나 이것은 예전 version의 wince (아마도 3.2. 이 책은 3.2를 기준으로 쓰여졌다.)에서만 유효한 설명일 것 같다. WINCE5.0에서 WINCEPROJ는 makefile이나 sources에서 주로 directory 이름을 나타내는데 사용되는데 이것이 current로 설정되는 경우는 전혀 찾아 볼 수 없다.

사용되는 방식을 검색해 보면 다음을 알 수 있다.
여기서 _PROJECTROOT는 "WINCE500\PBWorkspaces\내 PROJECT 이름\WINCE500\내 BSP 이름"을 나타낸다. public이나 private아래의 sources, sources.cmn, makefile들에서 정의된다.

1. Public 바로 아래의 directory이름(특정 기능을 지원하는 component들과 core OS component인 common)을 나타내기 위해 사용된다. private 아래의 sources.cmn이나 sources에서도 사용되는데, 이때는 _WINCETREE의 값은 common으로 설정된다. private에 존재하는 source code로 부터 생성되는 library나 target이 실제로 존재하는 있는 위치인 common아래쪽의 directory를 나타내기 때문인 것 같다.

2. Cefilter로 intialization file들($(WINCEPROJ).reg, $(WINCEPROJ).dat, $(WINCEPROJ).bib, $(WINCEPROJ).db)들을 처리하여 intermediate directory ($(_PROJECTROOT)\cesysgen\oak\file)에 저장해 두기위해 사용된다.

3. Makeimg에게 어느 module이 resource binding이 필요한지 알리는 file인 $(WINCEPROJ).loc을 intermediate directory인 $(_PROJECTROOT)\cesysgen\oak\target에 생성한다.

4. WINCEREL=1일때 intermediate directory($(_PROJECTROOT)\cesysgen\oak\file\)에 있는 intialization file($(WINCEPROJ).*)들을 $(_FLATRELEASEDIR)로 copy하기 위해 사용되기도 한다.

즉 component를 나타내는 public아래의 directory를 나타내기 위해, initialization file의 이름을 나타내기 위해, makeimg에게 어떤 module들이 resource binding이 필요한지 알려주는 loc file의 이름을 나타내기 위해 사용된다.
또 아래의 내용을 좀더 보면 알겠지만 WINCETREE는 정의되지 않고 WINCEPROJ만 정의된 경우 WINCEPROJ project인것을 나타내기 위해서 사용된다.

WINCETREE
검색해 보면 다음을 알 수 있다.

1. Public아래의 common을 포함한 각 component directory에 있는 sources.cmn에서 그 component directory 이름을 나타낸다.

2. Makefile.def의 내용에 따르면 sources file이 include되기 전에 _COMMONPUBROOT와 __PROJROOT값을 정의한다. 이때 다음 각 경우에 따라서 다른 값으로 정의 된다.

*sysgen중 인 OS project - unsysgened input libs들을 가지고 있고 결과물이 projectroot\cesysgen에 생긴다.
OS projects during SYSGEN (which get unsysgened input libs & build into projectroot\cesysgen)
_COMMONPUBROOT=$(_PUBLICROOT)\common
__PROJROOT = $(_PROJECTROOT)\cesysgen


*compile중인 OS project - unfiltered header file들을 가지고 있고 결과물이 자신의 public tree에 생긴다.
OS projects during compile (which always get the full unfiltered headers & build into their own public tree)
_COMMONPUBROOT=$(_PUBLICROOT)\common
__PROJROOT = $(_PUBLICROOT)\$(WINCEPROJ)


*WINCEPROJ project - 이미 sysgen된 header와 lib들을 필요로 하지만 결과물은 자신의 public tree에 생긴다.
WINCEPROJ projects (which want sysgened headers & libs, but want to build into their *own* public trees)
_COMMONPUBROOT=$(_PROJECTROOT)\cesysgen
__PROJROOT = $(_PUBLICROOT)\$(WINCEPROJ)


*일반 user project - 이미 sysgen된 header와 lib들을 가지고 있고 결과물은 최종 project public tree에 생긴다.
regular user projects (which get sysgened headers & libs & build into the final project public tree)
_COMMONPUBROOT=$(_PROJECTROOT)\cesysgen
__PROJROOT = $(_PROJECTROOT)

OS project란 sources.cmn에서 WINCETREE가 정의되어 있으며 public\WINCETREE\cesysgen\makefile이 존재하는 것을 이야기 한단다.
따라서 WINCETREE 자체는 public\WINCETREE\cesysgen\makefile의 존재를 확인하기 위해서, 현재 OS project compile중 이란 것을 나타내기 위해서 사용된다.

OS project와 WINCEPROJ project
OS project compile중인가 아니면 WINCEPROJ project중인가에 따라서 결국 어디에 dependency를 가지며 어디로 결과물이 생긴다는 것이 정의된다.
WINCEPROJ project - sysgen중이 아니고 WINCETREE가 정의되어 있지 않으면서 WINCEPROJ만 정의된 것으로 이때는 sysgen의 결과물에 dependecy를 갖고 자신의 public directory에 결과물이 생성된다.
OS project - WINCETREE가 정의 된 것으로 sysgen되기 전의 unfiltered header file에 dependency를 갖고 결과물은 자신의 public directory에 생성된다. (sysgen은 OS project에 대해서 이루어 진다는 것은 당연한 것라 하겠다.)

다 써놓고 보니 내가 봐도 무슨소린지 잘 모르겠다는 생각도 든다.
역시 Windows CE에서 제일 어려운것은 BUILD다.

금요일, 6월 20, 2008

WINCETARGETFILE0와 WINCETARGETFILES

WINCETARGETFILE0
sources file내에서 이 macro가 정의되어 있다면 현재 sources와 source code들이 있는 directory내의 makefile.inc가 (optional한 file로써 custom build rule이 필요할 때 추가해 준다) central makefile의 흐름상에 추가되어 현재 directory의 build를 위한 custom rule를 정의한다.

이것은 한마디로 해당 directory 내의 source code들을 build하기 전에 custom rule로써 처리 해 줘야 할 target을 정의해 준다.

central makefile인 makefile.def의 All target의 dependency list의 제일 앞에 추가 된다. 즉 다른 무엇보다 제일 먼저 custom rule로 처리되는 녀석을 나타낼때 쓴다.

WINCETARGETFILES
이건 WINCETARGETFILE0와 같은 기능을 하는데 단지 makefile.def의 ALL target의 dependency list의 제일 뒷쪽에 추가된다는 것이 다르다. 즉 이것은 다른 모든것들이 처리된 다음에 제일 마지막에 custom rule로 처리되야 하는 녀석을 나타낼때 쓴다.

이것들은 흔히 어떤 file들을 intermediate directory에 때로는 이름을 바꿔서 copy하는 경우에 사용된다.


예를 들면, sources file에서 다음과 같이 정의되고
TARGETNAME=waveui
WINCETARGETFILES=$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\waveapi.res

makefile.inc에서 다음과 같이 정의되어 있다면
$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\waveapi.res:$(_OBJDIR)\$(TARGETNAME).res
copy $? $@

이게 무슨 뜻인가?
단지 $(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\waveapi.res을 $(_OBJDIR)\waveui.res로 이름을 바꿔서 copy하라는 소리다.

_DEPTREES

이것은 windows ce project가 의존하는 directory를 나타낸다.
이 directory내의 결과물들(target이나 library들)이 현재의 windows ce project build에 사용된다. 따라서 이 directory는 현재의 windows ce project가 build되기 전에 미리 build되어 있어야 한다.

화요일, 6월 03, 2008

G.711과 PCM

G.711은 흔히 말하는 PCM(pulse code modulation)과 같은 것 입니다. Analog signal을 digital화 하기 위해 sampling하는 방법을 이야기 합니다. 그중 전화통신 응용에서는 8bit resolution에 64kbps의 bit rate을 사용하는데, 이것은 8khz(64*1024/8) sampling rate을 갖고, 각 sample은 8bit로 표현된다는 소리입니다.
G.711이 그냥 PCM과 다른 점은 이렇게 전화 통신에서는 8bit resolution, 8khz sampling rate으로 표현하므로 발생하는 음질의 감소를 보정하기 위해서 각 sampling 값들을 특정 값들로 대치하는 방법을 사용하고 이때 사용되는 sampling 변환 table에 따라서 두가지 방식이 사용된다고 합니다. Mu-law standard는 북미와 일본에서 사용되고, A-law standard는 유럽국가들에서 사용됩니다.

Audio CD 이나 DVD의 경우 linear PCM이 사용됩니다.
Audio CD의 경우 2 channel, 16bit resolution, 44.1khz sampling rate PCM format입니다.
DVD 영화의 audio는 dolby digital이나 DTS에서 multi-channel surround을 지원하므로 8 channel에 (7.1 channel surround) 8, 16, 20, 24bit resolution, 48, 96khz sampling rate 까지 지원합니다.
DVD-Audio의 경우 24bit resolution에 192khz sampling rate를 지원합니다.

G.711이란 것은 telephone audio을 PCM 64kbps, 1 channel에서 encoding하기 위해, 그리고 이에따라 감소된 음질에 대응하기 위해서 sample 변환 table을 사용하도록 해서, ITU-T 국제표준으로 채택하면서 붙인 이름이라고 보면 될 겁니다.

화요일, 5월 13, 2008

TARGETLIBS와 SOURCELIBS

기존까지 "Building Powerfult Platform with Windows CE"에서 설명하는 데로 대충 이해하고 있었다.
그러다 최근 다시 생각해 볼 일이 있어 관련 내용을 찾아봤다.

Windows CE Help에는 다음과 같이 나와 있다.
TARGETLIBS
This macro definition specifies additional library (.lib) and object (.obj) files that should be linked into the target executable (.exe or .dll) file.

SOURCELIBS
This macro definition specifies library (.lib) files to be linked with the module specified in TARGETNAME.

This macro definition is typically only used when you are creating a new .lib file from other .lib files. Use TARGETLIBS macro when you are creating an executable (.exe or .dll) file.

마지막 부분은 SOURCELIBS가 나타내는 library들은 주로 새로운 TARGETNAME library를 만들기위해 사용되고, TARGETLIBS에 나열된 library들은 TARGETNAME executable을 만들기 위해 사용된다는 소리. (하지만 많은 경우 TARGETNAME executable을 만들기 위해서 sources file에서 TARGETLIBS와 SOURCELIBS가 같이 사용된다)

TARGETLIBS에서는 "linked into"라는 말이 사용되었고 SOURCELIBS에서는 "linked with"가 사용되었으니
TARGETLIBS는 target executable를 결과적으로 만들기 위해 link되어야 하는 것이고 SOURCELIBS는 build의 결과로 만들어진 TARGETNAME module과 link되는 것.
즉, TARGETLIBS + source -->TARGETNAME executable file
SOURCELIBS + TARGETNAME module --> ? (결과적으로 뭐가 된다는 것인지 나로서는 알수 없다)
이런 말인것 같다.
MICROSOFT website와 platform builder의 help에서 더이상의 자세한 정보는 찾아볼 수 없다.

Building Powerful Platforms with Windows CE에서는 다음과 같이 말한다.
page432
SOURCELIBS - platform dependent static libraries to be linked with source code
TARGETLIBS - libraries that must be linked with compiled source code
page288
The TARGETLIBS macro specifies object module libraries and import libraries (thoes used to reference the exported functions of a DLL).
The SOURCELIBS macro specifies modules that are linked not by unresolved symbols, but instead by the inclusion of all of the object modules contained in the LIB file in the final executable module.

이것은
SOURCELIBS는 source code와 link되는 것이고 TARGETLIBS는 compile된 source와 link되는 것.
Compiled source라는 말이 너무 모호하다. object file까지의 상태를 이야기하나 아니면 결과적인 module을 이야기 하나?
TARGETLIBS + compiled source code --> ?
SOURCELIBS + source code --> TARGETNAME module
TARGETLIBS는 static library, import library를 정의하고, SOURCELIBS는 static library를 정의한다는 말.
MS의 문서와는 완전히 다른 의미로 다가온다.

아래는 Wecom 게시물에서 찾은 것으로 google newgroup에서 퍼온거란다.
This is componentization feature of Windows CE.
The link has two steps.
First, whatever is in SOURCELIBS gets combined in a single library yourproductname_ALL.lib.
In the second step, executable module is linked from that library and all the targetlibs.

This is done to allow stubs to be conditionally linked:
If the function is defined into your source already, stubs get excluded.
If it is not there, stubbed version (returning ERROR_NOT_IMPLEMENTED or something to that effect) gets linked in instead.

If the link were to be performed in just one step, it would be impossible to predict which version (real or stub) would get included.
As it is, implemented functions have a priority over stubs.

(출처 : http://www.iwecom.co.kr/ce/advanced_read.asp?id=20906&vgoto=1&SearchString=Y&category=WF_wince)
이 글을 읽어보면 왜 SOURCELIBS가 static library를 나타내는지 알수 있다.
종합해 보자면, source code는 compile된 후 우선 SOURCELIBS의 static library와 link되어 target module이 되고, 이게 나중에 필요한 경우 다시 TARGETLIBS의 import library와 link된다는 말.
결과물이 TARGETNAME module이 SOURCELIBS와 우선 static하게 link되어 user defined function을 call하게 하는데, 만일 이게 없다 하더라도 나중에 dynamic하게 TARGETLIBS와 link되게 하여 stub function이나 stardard function이 call될 수 있게 하겠다는 것.


Google에서 발췌한 글을 읽자면 "Building Powerful Platform with Windows CE"의 내용이 틀린말은 아니라는 생각을 하게 된다. BPPW에서는 TARGETLIBS가 static libray도 나타낸다고 하는데 이부분은 확인 못했다.