解读WINCE 5.0 KITL代码流程

作者:WalzerLUPA开源社区$e&y5E)Zt c0K*Fo5g
日期:2005.3.19
}9fT3kF4h0Walser的网站LUPA开源社区 x+My@;R*j,q

LUPA开源社区$F/1wG0X+Qoiad

http://www.cnblogs.com/walzer/archive/2007/05/15/747327.htmlLUPA开源社区.Su0Pe1g;R

LUPA开源社区^ aF Lulh


_K9_2p4s#B8p{i/0m0摘要:KITL是PLATFORM BUILDER中的一个亮点,提供了和本地调试类似的断点、变量跟踪、内存查看等手段,如果没有KITL,嵌入式调试应该只能用串口打印消息来看了,工作效率大大下降。本文以实现最简单的SERIAL KITL为目的,就其实现代码进行跟踪调试,这些代码跨越了WINCE的PLATFORM、PUBLIC、PRIVATE三大主要目录,有些烦琐,不过只要能调通,一切工作和弯路都是值得的。我把调试经验和个人理解写下来,希望能帮助别人少走弯路。如果文章中有理解失当的地方,请不吝赐教。LUPA开源社区)J0g%Gq'f]f

5l~p2D A9xV8J2KU{0正文:LUPA开源社区 Nt.??F)CF
LUPA开源社区yu i;i V9tV l!Ad v
一.void OEMInit()  [platform/project/src/kernel/oal/init.c]LUPA开源社区G(v.Y:~n2~+m9f
    首先从OEMInit()函数看起。。在依次初始化Branch-Target Buffer、KERNEL函数、初始化中断、TIMER之后,就轮到KITL了。调用了这个函数OALKitlStart()。此时有个编译的分支,如果是RELEASE版本,那么在kernel/kern/stubs.c里面的OALKitlStart()函数是个STUB,只是return TRUE; 如果是DEBUG版本,那就进到kernel/oal/kitl.c里面的OALKitlStart().LUPA开源社区 Wh+Cr6r

LUPA开源社区$N?5Y~,yf&C

二.BOOL OALKitlStart()  [platform/myproject/src/kernel/oal]
Hd5g^ i5{5F'G0    在OALKitlStart()里面,首先试图从0xA00FF00处读取bootloader里面留下的kitl参量,如果读不到东西则使用该函数里的默认配置。由于原来用了ethernet同时作为download和kitl途径,所以在InitSpecifiedEthDevice函数里给pKitlArgs结构体赋值了。现在想把两者划分清楚,首先就把读取bootloader里面的kitl参量一句干掉,强迫使用我们在下面的默认配置。主要就是填充三个参量

x}M/MuaPf p%J0

#k3K/]G%}+` S3FU01.首先是这个结构体LUPA开源社区l sy;Q5b EUJc
OAL_KITL_ARGS pKITLArgs
Vo*X4Lb }.V0{LUPA开源社区:UOx_)b1pmLL
 UINT32 flags;  //设好ENABLED标志,按需要设POLL标志,但注意一定不要设PASSIVE标志LUPA开源社区d_,y'q%U3/z1o
 DEVICE_LOCATION  devLoc;
%lENR"Xm,@J/M0 {
{H y `K r.II;`+N0  DWORD  IfcType;  //不论ether还是serial,都是internal type =0;LUPA开源社区3y7geFwB
  DWORD  BusNumber; // =0
/Nt!o"X+ZlTYiR0  DWORD  LogicalLoc; //物理地址
#}3ssJ] gf8t7l0  PVOID     PhysicalLoc; //留做后面=OALPAtoVA(LogicalLoc, FALSE). 真见鬼, 感觉应该和上面的LogicalLoc作用调过来看着比较顺吧?
)ro {1fef0  DWORD  Pin;  //Ethernet才用的东东LUPA开源社区"/;o g Fy~ x(|.u
 }LUPA开源社区5o q/z2PF#kD
 unionLUPA开源社区wl4hC3OH T~{q
 {LUPA开源社区F*TBL o MU_2s^9c z
  struct
6QHo O~8u:I|5Y4S0  {
J cRAz+GeK0   UINT32  baudRate; //不用解释了LUPA开源社区 ghl.K N*ae_.h
   UINT32  dataBits;LUPA开源社区fE M&P-p0gO
   UINT32  stopBits;LUPA开源社区 }I%h5Z /-I i
   UINT32  parity;LUPA开源社区:vK5T,HR,Iy
  }LUPA开源社区n,p//J @
  structLUPA开源社区E1Fm-ei2Krp
  {LUPA开源社区j JIrV |,p
   UINT16  mac[3]; //这个也不用解释了LUPA开源社区/G5} P_w!G:so'a
   UINT32  ipAddress;LUPA开源社区)M;Vf1fl
   UINT32  ipMask;
IC |4sC!_ ^0   UINT32  ipRoute
M&[3o8e|6j0  }LUPA开源社区8?[5xU-d L
 }
bx$gKQ&n@C(AM%}@0}LUPA开源社区#BK/d/I)P1V
2. pszDeviceID.  感觉这名字就是起了好玩, 赋成Walzer应该比较拽,不过还是保留原来赋的AMOISOFT好了, 免得被打.
#w9v2LW,f7[7WBE03. 全局变量OAL_KITL_DEVICE g_kitlDevices. 这个东东在kitl.c开头包含的kitl_cfg.h中被赋值,  最主要就是修改g_kitlDevices.pDriver.  这个pDrvier指向一个函数指针列表的结构体,该列表定义了用做kitl模块的初始化、读写、中断、流控制等函数。 g_kitlDevices本身是个二维数组, 可以定义许多设备用做kitl时提供的参数设置, 后面会用一个for来循环判断pKITLArgs的参数和g_kilDevices里面哪个一维数组成员相匹配.LUPA开源社区6y e'YV.c7gcB

LUPA开源社区s/E[g/s(a

这三个参量填充好以后,就可以进到OALKitlInit(pszDeviceID, pKITLArgs, g_kitlDevices)里面了.LUPA开源社区bX${(f4RA7KI-aw

&f`Lo q0f?C0三.BOOL OALKitlInit( deviceId, pArgs, pDevice)    [platform/common/src/common/kitl/kitl.c]
)Z(hB2N,m#p n0    这个函数先把输入的参量全部用OALMSG打印出来,这个不管。LUPA开源社区n`-Y'Q d({0j g
    重要的是引入了g_kitlState全局变量,开头一句
$i H*@a$Tg1U5Qc0    g_kitlState.pDevice = OALKitlFindDevice(&pArgs->devLoc, pDevice) 这个就是上面所说的从g_kitlDevices里可用设备列表里循环判断,找到选用的设备的匹配函数指针。
9H./9|t%C1uSh`1b9N0    接着把输入参量devicdId和前面填充好的OAL_KITL_ARGS结构COPY到g_kitlState里面LUPA开源社区 F(Hlk[8w9_
    然后就可以调用KItlInit(TRUE)了,如果前面在FLAG里面设了PASSSIVE标志,现在就是KitlInit(FALSE)了,嘿嘿爽到了吧。

5a3W'vMs+Gq0

[#pZ[L!N:w/mw0四.BOOL KitlInit(BOOL fStartKitl)    [private/winceos/coreos/nk/kitl/ethdbg.c]LUPA开源社区 O yhx4i"m F
    太猥琐了,我要用串口,它居然叫ethdbg.c,不给面子。不过是private里面的东东,可远观而不可亵玩焉~~
i)|o#V3a iwR0    这个函数干了三件事:LUPA开源社区VIPnD
1. 装载了三个全局的函数指针
8e6|k7nc-~02. 用NewClient注册了三个KITL客户端:LUPA开源社区y$SS4[}q#T~'U%w ?
    KITL_SVCNAME_DBGMSG   //debug message, Debug信息发布通道LUPA开源社区D2l2f!Yq9WgycY)|
    KITL_SVCNAME_PPSH  //PPshell, 文本控制台界面 LUPA开源社区4T0[%WE1g W8xk*f9b
    KITL_SVCNAME_KDBG //kernel debug, 内核调试界面

/ _8B}({7VU nG0

;`3y5`dL/t03.由fStartKitl来决定是否启动StartKitl()函数. (这里顺便提一下,按照匈牙利命名法, BOOL变量前面加个b, 但MS的做法我觉得很合理, BOOL变量就是个FLAG嘛, 前面加个f, 把小b留着给BYTE类型用.)

A%q:HRp2u!P7S:P0

,|6Q%?[bQ0五.static BOOL StartKitl(BOOL fInit)    [private/winceos/coreos/nk/kitl/ethdbg.c]LUPA开源社区Nb.R2xAE-i
    这又是prviate里面的东东。最痛苦的地方开始了。这函数及其子函数将第一次调用OEM自己写的KITL模块初始化、读写程序。是骡子是马,拉出来溜溜就知道啦~LUPA开源社区[&O&H9_^1l&X$Dsg
    按顺序看下来,首先判断输入参量是否要启动KITL,并且如果KITLGlobalState里面被打上KITL_ST_DESKTOP_CONNECTED标记的话,那下面的步骤就全免了。当然我们是第一次运行到这里,若这么就跳出的话,俺就马加爵了。LUPA开源社区./#?4UpY V6if'n3s

U.KDf._0k%h;lF0    第一步:
'd%|w2a;A'b uE_0    干的第一件正事就是调用OEMKitlInit(&Kitl). 这个后面详述. 继续把这个函数看完.LUPA开源社区/BAAo:}ImQ v
    OEMKitlInit初始化KITL的硬件抽象层后并把相关指针数据填充给全局变量KITLTRANSPORT Kitl (有没有搞错,为什么不叫g_kitl), 这些工作做完就返回了LUPA开源社区7M2z Q{P2K2V
     StartKitl收货后把Kitl结构整个检查一遍,保证没错后, 马上买单, 把全局变量KITLGlobalState打上个KITL_ST_KITLSTARTED标记. 这才算KITL启动的第一步OK了.

6h(L(R A(B/N~j_1f0

(f M)h+n,C+hO0    第二步:LUPA开源社区'T1g9{ x p
    接下来就是KITLConnectToDesktop(), 进这个函数后就是第一次使用了前面KITL传输介质硬件抽象层里的读写函数了, 这时候就需要调试了. 这个ConnectToDesktop大致就是先Send了一个kITL.....的frame过去,然后polling等待PC端的response, 那边再发个kITL.....的frame过来, 搞得跟地下党打暗号似的, 其实也没什么玄乎的,就是普通的数据包前面加个KTIL专用的HEADER而已. 这个CONNECT成功后,KITLGlobalState里面就加个KITL_ST_DESKTOP_CONNECTED标记了.LUPA开源社区[TN;G1W{

/?*T.m&]&N0e*xY*Jyq0    第三步:
awm#Q)Bg0h t0    set up kernel function pointers, 也没什么,就三个函数指针, 赋完后就KITL_ST_ADAPTER_INITIALIZED了. 其实这个KITLGolbalSate的总共有7个标志,分别是LUPA开源社区o5L)JRQ
KITL_STARTED,  (OK)
TS+C U*i,r J0`/0DESKTOP_CONNECTED,   (OK) LUPA开源社区#An&g.U*S#Scx
TIMER_INIT, (?)
Ir*_Bq0INT_ENABLED,  (POLLING)
0F_7swm+fY r!@-H+k]0IST_STARTED,  (POLLING)LUPA开源社区y#t3XYJd7ep
MULTITHREADED,   (?)
.ID!^S(_0ADAPTER_INITIALIZED. (OK)
NCn4PEr8G0后面括号里打上OK是到这里已经完成的, 打问号的我还不太清楚什么作用, INT和IST两项,我们用的POLLING所以肯定是不需要了.

b?D^zI!d0LH:|5?0

W2y+c/&~7~&M0    第四步:
7jL0t:zq0G;nb0    调用SetKernelCommDev设置kernel通过何种介质传送DBGMSG, PPSH和KDBG.LUPA开源社区#X9l"O.S~V&N t /
    OHYEAH, 我的SERIAL KITL就夭折在这里. 进到SerKernelCommDev(service, CommDevice)函数里看, 它只认CommDevice=KERNEL_COMM_ETHER的情况,而屏蔽了与ETHER并列的SERIAL和PARALLER,直接return FALSE, 下面的事情都不用干了. 而在MS提供的WinCE Documantation里面,这个SetKernelCommDev函数的说明上写着"This function is obsolete and should not be used". 若想改嘛,这个是在private里面的还动它不得. NND, 感觉被MS raped了.
NKE Pn#u&Oq^0     如果使用ETHER在这里成功的话, 下面还有两个函数NKForceCleanBoot()和KITLInitializeInterrupt()走过去, 这KITL初始化就全部结束了. 我估计KITLGolbalSate里面的INIT_ENABLED和IST_STARTED就是在这个函数过程中被标记上的.LUPA开源社区#k+b7[w_
    
I3]+@$k0C b0   
*m g9Cqu0六.BOOL OEMKitlInit(PKITLTRANSPORT pKitl)    [platform/common/src/common/kitl/kitl.c]
SYDNk:KR1^0R)w0    前面提到StartKItl起来后,首要的就是调用OEMKitlInit. 这个函数在WinCE4.2和5.0里差别很大, 4.2里的做法是    if (!InitEther (pKitl) && !InitParallelSerial (pKitl)), 把ETHER, SERIAL, PARALLEL都初始化了一遍,碰运气看哪个用得上,而5.0里是进来后就一个很明显的分支剧情,由g_kitlState.pDevice->type来决定是调用OALKitlEthInit还是OALKitlSerialInit. 典型的种族歧视, 居然没有OALKitlParallelinit. 还好我们用的是SERIAL.LUPA开源社区n)gnyj6D
    这里有个选择编译的地方,就是#ifdef KITL_ETHER和#ifdef KITL_SERIAL, 具体定义的地方是该目录下的sources文件里面一行 CDEFINES=$(CDEFINES) -DKITL_SERIAL -DKITL_ETHER, 猥琐啊找了半天. 其实我觉得既然有if结构来选了,那么选择编译也是可有可无的了.
(N"/(U p'v2n0    好,下面就进到OALKItlSerialInit()里面.

pJ(V!]3{@8h!T0

:e5f2IA}1e y/,M9E)x0七.BOOL OALKitlSerialInit(LPSTR deviceId, OAL_KITL_DEVICE *pDevice, OAL_KITL_ARGS *pArgs, KITLTRANSPORT *pKitl)
9J4N^ V(F2Ivp|0    [platform/common/src/common/kitl/kitlserial.c]LUPA开源社区s)a|Ku8ec
    我自己往这个kitlserial.c文件里写了六个函数.
LnA] g-Enxc Ri0    BOOL KitlSerialInit(KITL_SERIAL_INTFO *pSerInfo)
!C BP1`"j:E0    UINT16 KitlSerialWriteData(UINT8 *pch, UINT16 length)LUPA开源社区&tu} BFi
    UINT16 KitlSerialReadData(UINT8 *pch, UINT16 length)
Q&Ty6e*`$e2T0    void KitlSerialFlowControl  //stub, 我所用的FFUART只有TXD和RXD两根线, RTS等都没有, 所以FlowControl自然也应该是STUB了LUPA开源社区(V i`0O8U @i
    void KitlSerialEnableInt(void)   //stub, use pollingLUPA开源社区(i+KB:a ycwz
    void KitlSerialDisableInt(void)  //stub, use polling
QG'o-~ h"z6w0    否则前面的g_kitlDevices里面没有相应的硬件抽象层来填充.LUPA开源社区G|$QI!um"_
    上面的SerialRecv, Encode, Decode等就意思都很明显了,不用多说. OK现在已经走到最底层了, 文章也可以结束了.

O(xYO%y-MM0

{1qW.E s`Yl0八、记录一下调试经验LUPA开源社区 q3l/.ob z-a
    虽然这是我第三次调串口了,由于没总结前面的经验,还是耗了两天才到private里面夭折的地方。实际上应该一天就能走到了。问题出在
^TzP8l*E01. 第一天调试器根本用不上手。调试器软件、PB不断死翘,经常重启软件甚至重启电脑,第一天有3/4以上的时间耗在这些问题上, 不断重启。LUPA开源社区Y$G4wa F8~#G
2. 在UART初始化函数的最后,居然忘记了在interrupt controller register里面enable uart unit, 这么乌龙的事。LUPA开源社区o`5}.L j0m;dH6}N
3. KitlSerialFlowControl的问题. 写的时候照搬了X86下的函数, 没想明白到底要Control什么. 调试时死在这里后,  一开始把指向这个函数的指针设置成NULL, 但这样PRIVATE里面有些要IF判断的函数就进不去了. 后来换成STUB就OK了.LUPA开源社区ZW;g#u#j/^Pvq;}:Z
4. receive函数里面, 在收每个BYTE之前先去判断了Line Status Register里面的Data Ready bit, 如果该为零, 则返回失败. 但这里是有问题的,具体也没太想明白, 反正在调试debug serial的时候就把这个判断从MS提供的源码里头删去了,现在做KITL serial时又手痒加进去, 果然还是不行. 这可能是MS或INTEL的一处BUG, 但按照INTEL CPU MANUL UPDATE里面给的读流程, 一开始只判断LSR里面的ERROR, 没有判断DR位就开始读第一个BYTE了. 读过后再判断如果DR位为1,则继续读下一BYTE.LUPA开源社区8E_1mH4v%m$H
5. 在receive函数里加通过debugger加break point, 结果receive buffer register里面的数据被debugger扫描去以后,就变零了,CPU上却什么都收不到, 这事情耗了大半个下午,最后还是Jeffery发现的这个问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值