4.25.2007

WINCE Serial Port

Serial 使用 serpddcm, com_mdd2 兩個library。
  • Serpddcm : PUBLIC\COMMON\OAK\DRIVERS\SERIAL\SERPDDCM
  • com_mdd2 : PUBLIC\COMMON\OAK\DRIVERS\SERIAL\COM_MDD2
MDD 中,每個port的處理靠 HW_INDEP_INFO 這個structure (serpriv.h)。
HW_INDEP_INFO 中的 pHWObj 指向 PDD object。

在 COM_Init 中,會由 GetSerialObject(DevIndex) 產生一個PDD Object 的"空殼"。
DevIndex 是由 registry key 中取出的。
GetSerialObject( ) 在 serpdd.cpp 中。

GetSerialObject( )除了allocate object 外,還initialize object,object 中重要的property是 pFuncTbl。

從名字就知道,pFuncTbl 是function table,宣告在 cserpdd.cpp 中。
__HW_VTBL *pFuncTbl
__HW_VTBL 宣告在 serhw.h (OAK\INC)。
名稱宣告和cserpdd.cpp中宣告的function table實體不一樣 (煙霧?)。
但是大概是把 開頭的"HW"改成"Ser"。

真正create出pdd實體的function 是 上面Funtion Table中的 HWInit( ),也就是 SerInit( )。

SerInit( )呼叫Platform\Driver\Serial\ser_xxx.cpp中的CreateSerialObject( )生出CSerialPDD物件。
MDD至此和PDD相關了。
CreateSerialObject( )的argument : DeviceArrayIndex,是從registery讀出來的。
被用來指定mcu上實體的serial port (port 0, 1, 2,,,etc)。
switch(DeviceArrayIndex){
case 0:
pSerialPDD = new CPddXXXSerial1(...);
break;
case 1:
pSerialPDD = new CPddXXXSerial2(...);
break;
case 2:
pSerialPDD = new CPddXXXSerial3(...);
break;
}

return pSerialPDD;
所以修改registery中的DeviceArrayIndex,就可以改變comport mapping。




Send Data Out的calling route:

mdd.c : COM_Write : DoTxData
mdd.c : DoTxData : pFuncTbl->HWTxIntrHandler
經過 HW_VTBL , 指向 SerTxIntrEx
cserpdd.cpp : SerTxIntrEx : XmitInterruptHandler

XmitInterruptHandler 是 CSerialPDD 的virtual function。
實際的 platform pdd driver繼承自CSerialPDD,所以都要implement這個virtual function。


platform 的serial driver也分為兩個部份,因為通常target都不只一個serial port,所以利用 class 的方式 由parent class 產生許多實際的serial port class。

parent class : pddplatname.cpp : CPddPlatUart 繼承自 CSerialPDD
child class : ser_platname.cpp : CPddPlatSerial1[2.3....] 繼承自 CPddPlatUart


所以serial port的PDD有兩部分:
  • PUBLIC : CSerialPDD (virtual)
  • Platform : CPddPlatUart/Serial (implement)
這部份有點用到design pattern 的Factory。
在 platform 的source code中有: CreateSerialObject ( ),依照argument生出對應的 platform object 。


另外 COM driver 是 uart和IR共用的,所以在IOControl 中有 IOCTL_SERIAL_ENABLE_IR 用設定該 COM port是IR還是uart使用。

該IOCTL 呼叫 pFuncTbl->HWEnableIR( )
HWEnableIR ( cserpdd.cpp : SerEnableIR ) 呼叫 pSerialPDD->SetOutputMode(TRUE, FALSE)
SetOutputMode (pddplatform_ser.cpp) 呼叫 ... platform implement 的 CPddPlatformUart :: SetBaudRate( ) ..
但是很奇怪的是 這個function 沒有refence enIR 這個argument。

IR 和UART的差異除了baudrate generate不一樣外,還有UART是全雙工,可是IR半雙工。所以在 XmitInterruptHandler ( ) 中,作TX時,會呼叫Rx_Pause( )將Rx關閉。
並且由IR Setting bit (hardware register)決定,需不需要等TX complete,然後把RX再打開。

Rx_Pause( )也是一個Virtual function,所以實際implement時,如果該port 是要作 IR用,就要implement這個function (將RX關閉,打開)。

如果不作IR用,就不能implement這個function ,否則,因為 XmitInterruptHandler( )的行為,反而會使 Rx發生問題。

沒有留言: