월요일, 11월 03, 2008
Windows CE에서 Arabic locale 사용하기 (아랍어 build)
금요일, 10월 10, 2008
Makefile에서 :: (double colon, two consecutive colon) 은?
이것은 두개이상의 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를 바꾸기
- WINCE600\PUBLIC\COMMON\OAK\DRIVERS\WAVEUI 로 이동
- build -cp
- sysgen -p common waveapi
- 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 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로 정의된다는 것을 알게된다.
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
'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에 의해서 만들어지는 아닌지는 일반 editor의 find in files기능을 사용해서 전체 sources file중에 gwes_lib등의 lib 이름이 있는지 찾아보면 알수 있다.
쉽지 않다.
난 wince에서 build가 제일 어렵다.
Touch calibraion화면 문구중에서 keyboard관련 내용 없애기
그러나 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 상태 창 제거하기
이것을 안보이게 하기 위해서는 다음의 registry 설정을 한다.
[HKEY_CURRENT_USER\ControlPanel\Korean IME UI\Settings]
"ShowState"=dword:0
수요일, 9월 17, 2008
MS환경에서 file들 합치기. 이어서 연결하기. concatenate files
cmd.exe를 실행한다.
다음을 입력한다.
copy /b a.txt+b.txt+c.txt abc.txt
토요일, 8월 23, 2008
Protected Server Libraries 2 - PSL의 구현
소개
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의 구성요소들
- PSL상의 function들 (entry point들)
- 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값이 할당되어야 한다.
- 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들을 정열한다.
- 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 - 기본 개념
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
나의 인생 나의 기타
월요일, 8월 11, 2008
Windows CE debugging tips
그 blog는 아직 남아 있지만 온통 장문의 영어로 된 글들이라 도대체 다시 읽을 엄두가 나지 않았다.
이번에 다시 한번 극기하며 공부하고 나중을 위해서 요점을 이곳에 정리해 두어야 겠다는 생각이 들었다.
사실 내 blog의 애초 주요 목적도 그것이었다.
많은 것을 매일 매일 배워나가지만 어느 하나 지속적으로 오래 사용하지 않으니 금방 잊어버리고, 다시 필요한 일이 생기면 처음 시작하는 마음으로 다시 공부해야 한다. 공부를 막 마쳤을 때 생생하게 이해하고 있는 내용을 쉽게 풀어 기록해 놓으면 다음에 잊어버렸다가 다시 필요해 질때 처음부터 다시 공부해야 하는 수고를 좀 덜지 않을까 하는 생각이 들었다. 생각해 보면 대부분의 쓸모있는 전문 정보들는 거의 영문으로 되어있다. 웹상에 한글 정보들은 대부분 놀고 먹고 즐기는 내용들뿐 정말 필요한 전문적 지식들은 거의 찾아 볼 수가 없다. 한국 인터넷 문화의 부끄러운 단면이라고나 할까?
목요일, 8월 07, 2008
WINCEOEM, _OEMINCPATH, _ISVINCPATH
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 구조 설정
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 출력이 가능할까?
질문
흔히 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)
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일 새벽 촛불집회
금요일, 6월 27, 2008
목요일, 6월 26, 2008
아버지와의 논쟁
그러다 이번주 월요일 아버지랑 소주한잔 할 일이 있었는데, 피하고 싶었던 현 촛불집회와 정치 경제적 상황에 대해서 논쟁이 있었다. 경향신문이 좌파적이고 선동적이란 말도 하셨고...
몇 년전부터 나는 아버지와 이런 류의 대화를 의도적으로 피하며 그냥 받아들이는 자세를 보여 왔는데, 내가 그래왔던 이유는 아버지를 결코 논리적으로 설득할 수 없고, 부모를 이기는 것은 무상한 일이며 부모님께 상처만 남길 수 있다는 것을 알기 때문이다.
오늘자 한겨례 신문에서 내 느낌을 잘 표한하는 글을 보게 되었다.
김어준의 그까이꺼 아나토미
삽화에 다음과 같이 쓰여 있다.
"지난 대선 언저리의 기억 한토막. (택시운전)기사는 육두문자를 써가며 빨갱이 정부를 성토했고, 이제 한두달 후면 새 시대가 올 것이라 확신했으며 그 시대를 이끌 지도자는 단연코 이명박 이었다. 나는 한마디 대꾸 하려다 그의 깊은 주름을 보고, 그만 두었다"
그리고 김어준은 이야기 한다. "그러나 장인(혹은 부모)을 개안시키려는 남편의 시도도 무망하다. 그건 그것대로 부모 세대의 존재양식이었기 때문에. 부모를 바꾸려는 모든 시도는, 그것이 논리적이지 않아서가 아니라 그들의 살아온 방식 자체를 부정하란 것으로 여겨지기에, 실패한다"
이 부분까지 읽는데 순간 가슴이 먹먹해 왔다.
수요일, 6월 25, 2008
FSRAMPERCENT
이 환경변수의 이름은 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
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
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
이 directory내의 결과물들(target이나 library들)이 현재의 windows ce project build에 사용된다. 따라서 이 directory는 현재의 windows ce project가 build되기 전에 미리 build되어 있어야 한다.
화요일, 6월 03, 2008
G.711과 PCM
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도 나타낸다고 하는데 이부분은 확인 못했다.