9.29.2007

Call DLL Function in class's way

CE 的DLL 有兩種使用方式 (ref : DLL有兩種)
一般使用自動link (ap load 時自動load)比較方便,因為幾乎和一般的library 一樣,沒有限制,所以整個class 可以export 出來,使用起來沒有限制 (不會因為是dll 而有特殊)。

但是另一種手動Load (ap 呼叫 LoadLibrary( )來load dll)就不一樣了。
要使用dll 裡export 的function ,要一一用GetProcAddress(inst,"functioname") 來取出。
所以,得到的是一個address。這樣,要 export 出 class 真是不可能了。(倒是codegguru有一篇hack...,示範怎麼作..)。

但是,還是有方法的。利用 address 的這個特性,將class 轉成pure function table (也就是都是virtual 的function),讓 ap 呼叫就可以了。

方法大概是這樣:

DLL 的部份:
Calc.h (借用那篇hack的code, 但是方法不一樣喔)..
class CCalcPI
{
public:
virtual int Add(int i,int j)=0;
};

class CCalc : public CCalcPI
{
public:
CCalc ();

int Add(int i,int j);
~CCalc();
private:
int use;
};
可以看到那個CCalcPI (Pure Interface)。就是要讓ap 使用的。
dll implement 的部份:
Calc.cpp
#include "stdafx.h"
#include "Calc.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

CCalc* inst=0;

CCalcPI* GetCalc()
{
if(inst==0)
inst = new CCalc();
return inst;
}

CCalc::CCalc()
{
use=0;
}

CCalc::~CCalc()
{
}

int CCalc::Add(int i,int j)
{
use++;
return i+j+use;
}
...順便implement一個singletone.
然後是dll 的def file:
Calc.def
LIBRARY   "Calc"

EXPORTS

GetCalc
ReleaseCalc

SECTIONS
.shared READ WRITE SHARED
export 出來的只有將constructor, destructor包裝起來的C function. (因為是singletone,所以destructor不必傳參數)。

使用:

App 要使用dll 裡的CCalc class,只能由CalcPI介面操作,必且由GetCalc( )取得CCalc class的實體:
    CCalcPI *calcp;
HINSTANCE hInst;
hInst = LoadLibrary(L"\\Windows\\Calc.dll");
if(hInst){

typedef CCalcPI* getcalc(void);

getcalc* fgetc= (getcalc*)GetProcAddress(hInst,L"GetCalc");
if(fgetc){
calcp = (*fgetc)();
int r = calcp->Add(1,2);

CString outstr;
outstr.Format(L"%d",r);
MessageBox(outstr);

CCalcPI* cp2=(*fgetc)(); // 看看singletone有沒有效 : by "use" variable
r=cp2->Add(1,2);
outstr.Format(L"%d",r);
MessageBox(outstr);
}
}

很奇怪,如果不是pure virtual class (CCalcPI),而是直接使用CCalc 的話,Linker會complain Add( ) function 找不到。

這一招其實是客戶教的....但是他的sample code把export function 直接放到class中,我不知道要怎麼作..

這一篇有類似的方法(好像更漂亮),但是我照作 link 還是有error。

9.27.2007

Linux Tiny : for small footprint

KernelTrap 上的文章

最近2.6 的kernel 越來越朝向大系統邁進,footprint越來越大,mips越用越兇。
越來越不適合embedded system和古老的(e.g 386) 機器。

所以有有人針對embedd system 和古老的機器,寫了一些patch,並且蒐集一些相關的patch,放在Linux Tiny 這個專案中。方便其他有需要的人。

偉大的Andrew Morton建議把patch都寄給他,他會把他放到他的-mm tree中。(真好)。

這個 elinux.org 有很多有用(趣)的文章喔,像這個 Kernel Size Tunning Guide ,就有詳細的 縮小footprint 的說明喔。

9.20.2007

OpenOCD , test run

OpenOCD 是一個很像以前 armtools 的專案,是利用jtag 控制arm core,而不是像samsung 的sjf 一樣,利用chip pinout boundary chain,控制pin out。

所以 OpenOCD 可以適用於所有使用arm core 的chip (而 sjf 只能用在samsung S3C24xx上)。

install:

follow 這一頁(http://openfacts.berlios.de/index-en.phtml?title=Building_OpenOCD)的說明,checkout openocd source。
因為公司有proxy,所以要用下面的command:
:~$svn co https://svn.berlios.de/svnroot/repos/openocd/trunk
然後到trunk 下。
:~$./bootstrap
這個command 需要automake 的aclocal,所以要記得安裝。
bootstrap會依據host system產生configure 這個script。
然後run configure.
:~$ ./configure --enable-parport
要注意 "--enable-parport" 這個option 要手動加入。否則他不會把parellel port 的interface 支援功能加入。
使用parallel port 的話,除了直接對io port access - include <sys/io.h> 外,也可以用/dev/parport0 的方式,就要增加 --enable-ppdev,但是我使用 --enable--ppdev 的code無法讓parallel port 正確動作。所以只好用 direct io port access (後來我還有改parallel port 的bios 設定,由"printer"改為"spp"

然後,開始make
:~$ make
之後,install (需要root 權限)
:~$ sudo make install
install 完後把他加上 S attrib,讓非root的user也可以使用 (direct IO access需要ioperm( ) )。
install 完後,可以試run看看..
:~$ openocd
Info: openocd.c:93 main(): Open On-Chip Debugger (2007-09-05 09:00 CEST)
Warnning: parport.c : 395 parport_init( ) : no parport specified, using default '0x378' (LPT1)
Error: jtag.c : 1253 jtag...
.OK。
因為我們有自己的jtag board,pin assignment 和wiggler 不一樣,所以要修改code。
parallel port pin assignment 在 src/jtag/parport.c,在line 97 的地方有支援的 parallel port dongle pin assignment 宣告。

所以新增一個entry : sjf..
 { "sjf", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
...這就是要作上一篇 jtag board sch 的原因。
後來發現pin definition 和 chamelen 一樣。
我們的小板子和 target board connector 有lay nTRST。但是到了parallel port board (74HC541) 就沒有lay nTRST。所以沒辦法控制 nTRST。
改好,make, make install。

修改config,原source 已經包含很多 cfg 的sample,在doc/configs 下。但是arm920t的cfg只有arm9_ft2232。

用 openmoko 的cfg 好了,比較接近..

到這個link(http://wiki.openmoko.org/wiki/Neo1973_OpenOCD) 去.. download openmoko 的openmoko.cfg
$ wget http://people.gta01.hmw-consulting.de/laforge/misc/openocd.cfg
修改一下..改為用sjf (剛剛改的...):
#daemon configuration
telnet_port 4444
gdb_port 3333

#interface
interface parport
parport_port 0x378
parport_cable sjf
jtag_speed 8

#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst #srst_pulls_trst

#jtag scan chain
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
jtag_device 4 0x1 0xf 0xe

#target configuration
daemon_startup attach
#target
target arm920t little reset_run 0 arm920t
#working_area 0 0x200000 0x4000 backup
run_and_halt_time 0 5000

#flash configuration (K9D1208V0M: 512Mbit, x8, 3.3V, Mode: Normal, 1st gen)
#NOR flash configuration (SST39VF400A 4Mbit, x16, 3.3V, 128sect, 4k/sect, 8 blocks (64kByte per block)
# flash bank cfg addr length chip_width bus_width target
#flash bank cfi 0x00000000 0x80000 2 2 0
紅色部份就是修改的地方,save成openocdsjf.cfg。

接上debug board,,, power on。開始..
$ openocd -f openocdsjf.cfg
Info: openocd.c:93 main(): Open On-Chip Debugger (2007-09-05 09:00 CEST)
代表openocd正確執行了....否則會有error mesasge..

openocd 是一個daemon,提供一個 telnet connection (port 4444) 讓user 溝通。
所以,另外開啟一個console..用telnet 連線..
charles@rbtlegacy:~$ telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
>
成功!出現command prompt!!

連上後,target system 還是可以正常執行,
下command: halt:
> halt
requesting target halt...
> Target 0 halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x60000013 pc: 0x338053a4
MMU: disabled, D-Cache: disabled, I-Cache: enabled
>
target system 停止,然後下resume:
> resume
Target 0 resumed
>
target system 又繼續動作,,,

command 可以在telnet 下help ,會列出:
> help
help display this help
sleep sleep for <n> milliseconds
version show OpenOCD version
shutdown shut the server down
exit exit telnet session
log_output redirect logging to <file> (default: stderr)
debug_level adjust debug level <0-3>
jtag_speed set jtag speed (if supported) <speed>
scan_chain print current scan chain configuration
endstate finish JTAG operations in <tap_state>
jtag_reset toggle reset lines <trst> <srst>
runtest move to Run-Test/Idle, and execute <num_cycles>
statemove move to current endstate or [tap_state]
irscan execute IR scan <device> <instr> [dev2] [instr2] ....
這些command可以看一下..有很多有用的command..
可以有些command 雖然有列出,但是沒有support,像...disassemble.

OH!! 可以attach CE machine,連上後,CE machine會繼續run,然後用halt 暫停,之後在用 resume 繼續run!!
halt 之後,可以用mdw 讀取任意位置的記憶體喔。
(但是因為mmu已經開啟了,所以address 藥用virtual address)。

"poll" 命令可以用來看arm core 目前的狀態 running, halt, or ?


有關openocd 的command,在openmoko和openocd的document都有說明,可以參考一下。
其中openmoko 這一篇,還說明如何用openocd作load image and run 的動作。

jtag board sch





printer pinout
printer register definition

330 GND A1 -- B6 -- C6
TCK A2 -- B5 -- C5 -- D14 -<<- D06 -- P02 : DATA0
TMS A3 -- B4 -- C4 -- D12 -<<- D08 -- P04 : DATA2
TDI A4 -- B3 -- C3 -- D13 -<<- D07 -- P03 : DATA1
nTRST A5 -- B2 -- C2
V3.3 A6 -- B1 -- C1 -- D20 - VCC
TDO A7 -- B7 -- C7 -- D09 ->>- D11 -- P11 : BUSY : status[7] invert
GND A12 -------------- Dxx GND

這個board的layout方式與openocd 中定義的 "chameleon"cable 一樣:

/* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
{ "chameleon",0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
但是沒有hardware reset 的功能 : trst。
另一個cable define "triton",和chameleon一樣,但是多了trst 定義:

{ "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
要改成 triton, trst 要 接到 printer port 的 DATA3 - P05

9.19.2007

挖地圖挺方便的


是利用googlemap 做出來的,輸入地址後,可以產生讓你內嵌的html code。copy 後就可以用囉。

地圖的大小可以自己決定喔。


http://wamap.net/

9.18.2007

Google Doc 出 簡報軟了

終於。
至此Google Document 算是完整了吧。
測試了一下。
http://docs.google.com/Present?docid=ajb6rhmm7kmw_1835v2k2k&fs=true
不像 試算表,有內謙功能,

但是在作presentation 時,有groupe 討論在旁邊(所以可以當作群組討論 ?)

9.17.2007

Build wxWidget with VS2005

Building wxWidget under VS2005.

先要安裝 Windows Mobile 5.0 Pocket PC SDK.msi - 雖然,我是要build for CE, not PPC。

get wxMSW-2.8.5.zip,解開。
用VS2005 開啟 build\wince\wx.vcw。
出現 convert ? 視窗,回答Yes.
然後就出現 "Cannot load the project dure to a corrunt project file"。
本來以為是wxWiget 的問題,所以去download 了其他版本,結果都一樣,還到new groupe 去問,想想,直接google 這一句error 看看...
是VS2005的問題,他不認識Unix file format,也就是說 換行符號要有'\r' 才行。
所以在linux 下解開,把所有build\wince 下的 *.vcp, *.vcw 用awk 修正..
awk 'sub("$","\r")' wx.vcw > wx.vcw.0
再用VS2005 開啟,就OK了。

然後build solution,出現"找不到clthumb.exe",改用 ppc2003 sdk 後,出現"找不到clarm.exe"。
這時候找 wxWidget wiki 就發現,有關WinCE 那一篇,用VS2005 的有說明
http://www.wxwidgets.org/wiki/index.php/Developers_Notebook-WxWinCECompiling
不可以用precompile header。所以將solution 下的project 一一修改後,rebuild,就OK了。
所以要注意每次build 後的report , "4 success, 2 fails"
一直 build, build 到沒有fail 為止。

實際上,我還是沒有成功,因為mono link 時一直出現找不到 wxjpeg.lib...

練習一下shell:
#!/bin/bash
mkdir ../newbuild
for file in *.vc?
do
awk 'sub("$","\n")' $file > ../newbuild/$file
done

9.14.2007

錄音 : Multimedia library

錄音 : 就是把 mic 的輸入 save成WAVE檔。
使用 Multimedia library,也就是 mciSendCommand( ) 這個function。
這個funciton 跟IoControl 類似,都是用command id + command structure 來傳遞資料。
所以很麻煩的每個動作都要準備好作為argument 的structure。

先 Open:
mciOpen.dwCallback = 0;
mciOpen.wDeviceID = 1;
mciOpen.lpstrDeviceType = TEXT("waveaudio");
mciOpen.lpstrElementName = "";
mciOpen.lpstrAlias = NULL;
dwError = mciSendCommand(0, MCI_OPEN, MCI_WAIT|MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
(DWORD)(LPMCI_OPEN_PARMS) &mciOpen);
if( dwError != 0 )
{
rtnMsg = "Open record device error; ";
return 0;
}
//save the Device ID
wRecordDeviceID = mciOpen.wDeviceID;
open 好的id 放到 wRecordDeviceID。 ( 這個以後作為對 錄音device 的control handle)。
然後,設定sample 格式
    DWORD dwFlags = MCI_WAVE_SET_FORMATTAG |
MCI_WAVE_SET_BLOCKALIGN |
MCI_WAVE_SET_CHANNELS |
MCI_WAVE_SET_BITSPERSAMPLE |
MCI_WAVE_SET_SAMPLESPERSEC |
MCI_WAVE_SET_AVGBYTESPERSEC|
MCI_WAVE_INPUT;
mciSet.wInput = 0; //recordsource index
mciSet.wFormatTag = WAVE_FORMAT_PCM;
mciSet.nChannels = 2;
mciSet.wBitsPerSample = 16; //8 or 16
mciSet.nBlockAlign = 4;
mciSet.nSamplesPerSec = 8000;
mciSet.nAvgBytesPerSec = mciSet.nSamplesPerSec * mciSet.nBlockAlign;
dwError = mciSendCommand(wRecordDeviceID, MCI_SET, dwFlags,
(DWORD)(LPVOID)&mciSet);
if (dwError != 0)
{
rtnMsg = "Not support specific record id; ";
return 0;
}
然後...
下command 開始錄音了..
    mciRecord.dwCallback = NULL;
mciRecord.dwFrom = 0;
mciRecord.dwTo = 0;
dwError = mciSendCommand(wRecordDeviceID, MCI_RECORD, MCI_NOTIFY,
(DWORD) (LPMCI_PLAY_PARMS)&mciRecord);
if(dwError != 0)
{
rtnMsg = _T("Not support specific record format; ");
}
然後,等等等...錄夠了..
叫他存起來:
    mciSave.dwCallback = 0;
mciSave.lpfilename = "TTTTT.WAV";
if( wRecordDeviceID != 0 )
{
mciGeneric.dwCallback = 0;
mciSendCommand(wRecordDeviceID, MCI_STOP ,MCI_WAIT ,
(DWORD) (LPMCI_PLAY_PARMS)&mciGeneric);
mciSendCommand(wRecordDeviceID, MCI_SAVE ,MCI_WAIT|MCI_SAVE_FILE,
(DWORD) (LPMCI_PLAY_PARMS)&mciSave );
mciSendCommand(wRecordDeviceID, MCI_CLOSE,MCI_WAIT ,
(DWORD) (LPMCI_PLAY_PARMS)&mciGeneric);
wRecordDeviceID = 0;
}
這樣就把錄到的資料放到 "TTTTT.WAV"這個file理了..

multimedia library 要include mmsystem.h
並且要 link Winmm.lib,否則會找不到 mciSendCommand( ) 這個function.
這個function 是假設你的pc 只有一個音效卡,在opendevice 時,直接指定 mciOpen.wDeviceID = 1 。

還有,要設定是用MIC還是LineIn 的話,在 control panel -system -hardware - audio 的


很愚蠢的,是"音量"那一個button,會出現右邊那個dialog.

VC6 to VS2005 的問題

VC 6 升級到VS2005 還是一些問題:
error C2440: 'static_cast' : cannot convert from 'BOOL (__thiscall CExampleDlg::* )(void)' to 'AFX_PMSG'
error 發生的位置是在 Message Handler 宣告的地方:
ON_BN_CLICKED(IDC_BUTTON1, OnButtonTestvoid)
google 結果是 ON_BN_CLICKED( )的handler function return 值是 void 才對,而我的code OnButtonTest( ) return 值是 BOOL。
所以.. 修改一下就OK.

還有..
error C2668: 'log' : ambiguous call to overloaded function
發生在statement:
expo = (log(num))/(log(10));
的地方,解法是..手動cast
expo = (log((double)num))/(log(10.));

9.11.2007

test google doc : 發佈功能

測試一下google doc 發佈內嵌的結果..

連相機都有open source 軟體 - CHDK (for CANON)

這一篇 How to give your low-end Canon digital camera RAW support

因為 CANON 的DIGIC II 引擎是arm core,而且有人又找到load program into ram 的方法,所以有了這個專案 : CHDK

專案含full source code and build instruction. (ref CHDK Wiki)

load firmware 的方法是利用SD Card,是在執行時load,所以不會erase 掉原來的firmware (not sure)。

這個軟體新增的功能有:
  • RAW 影像檔
  • Zebra 模式 (在preview 中機過曝與不足區域標示出來)
  • live histogram 顯示
  • game.
  • sd file browser
  • battery voltage
  • script 執行能力 (snap and shoot with specify shooting parameters)
所以,hacker 們,去買台CANON 相機吧!

9.10.2007

software reset implementation : watchdog or software jump

真的見識到..

software reset 發生問題...
因為是利用 watchdog reset 機制做出software reset 的動作。
以往沒問題的版本是用 jump 動作 (jump 到 start point)。

所以.. 修改 .. 改為software jump 。

本以為 software jump 要模擬 watchdog reset 的動作,在reset 前將所有 hardware power (GPIO )關閉,將 週邊register (LCD, USB, CLK...etc), reset。
結果導致 啟動後 LCD 沒畫面 (白畫面)。
但是從 boot prompt sound 判斷,似乎OS有boot 起來。

所以 ..,, 把所有"模擬watchdog reset 的code" 移除掉後..
就OK 了。


Software Jump 和 Watchdog reset 的差異:
  • Watchdog reset : 啟動 watchdog reset,讓他timeout,發生 watchdog interrupt。watchdog reset 會reset program counter。讓 cpu 由 0x00 開始執行。
  • Software Jump : 自己寫code,跳到 0x00 執行。

其實還有一項奇妙的東西...

0x00 開始的bootcode,會利用 週邊暫存器 來判斷是 hardrest (cold boot : register 會被清空) 還是 software teset (該register 不會被清空)。決定要 load image from nandflash (hard reset)再jump to ram 或是 直接jump to ram (software reset)。

hardware reset 的jump address 和 software reset 的 jump address 不一樣。
差距 0x1000。 (0x30200000 和 0x30201000)
但是看 0x30200000 該處的code ,就是一個 jump 到 0x30201000 的instruction。
所以jump 到哪裡都一樣呀。

但是 software reset 的jump 一定要jump 到 0x30201000,不然的話會boot 不起來.

Robert 說:唯一的可能就是 Software reset 後,代表0x30200000 該處的code 已經被修改了,不是 jump 到 0x30201000。
如果是這樣的話... CE kernel 真是博大精深呀,是 self modify code

9.05.2007

PPC 2003 SDK : unresolved external symbol "const type_info::`vftable'"

原來用CE SDK 都沒事,改用PPC SDK build,出現
unresolved external symbol "const type_info::`vftable'"
google 到這一篇:The Run-time Type Information library for the Pocket PC 2003 SDK is available,原來是PPC 2003 SDK 的STL沒附 RTTI。

但是 MS已經在2004 年很好心的補上這個 library。

  1. download 後,解開,會有Armv4, emulator 兩個folder,裡面有 ccrtrtti.lib(pdb)。
  2. 將這兩個檔案 copy 到對應的 C:\Program Files\Windows CE Tools\wce500\Amber SDK 003\Lib\ARMV4I 和 (emulator) 下。
  3. 修改 eVC 的Project,在 Project Settings -- Link 的 object/library module 中加入 Ccrtrtti.lib。
  4. 在 Project Setting -- C/C++ 的option 中加入 /GX option。
注意,所有使用 ppc 2003 sdk 的都要加上以上修改,並非在library project 才加。
重新build (link)後,就可以了。

9.04.2007

VS2005 for smartphone 2003 device "bootstrap could not be loaded"

上一篇,可以用VS2005開發smartphone application。不必用 eVC。
但是在 debug 時,卻會出現 "bootstrap could not be loaded" 的error。
google 說 ..

因為VS 的debug channel 使用不一樣的方式,不是用 active synch。
所以要改回activesynch 的話,就要裝ActiveSynch,然後把

%userprofile%\Local Settings\Application Data\Microsoft\CoreCon\0.1

這個folder 刪掉,重開VS2005。
VS2005 就會重新create一個用ActiveSynch 作debug channel 的 0.1 folder 了。