本文集中讨论StartKitl函数中KITLConnectToDesktop过程。 在OEMKitlInit()初始化KITL硬件介质后,KITLGlobalState状态里被打上KITL_ST_KITLSTARTED标记,KITLConnectToDesktop完成后则会有KITL_ST_DESKTOP_CONNECTED标记。这是继续往下运行完成StartKitl的重要一步。在KitlConnectToDesktop中,将首次调用到OEM层对KITL介质的读写函数。 我们依次看下来。KITLConnectToDesktop可以分为两大部分, 首先是发送过程。进入KITLConnectToDesktop后,马上填写要从target发送到PB的数据包。 PKITL_HDR pHdr = (PKITL_HDR) (PpfsFmtBuf + Kitl.FrmHdrSize); PKITL_DEV_TRANSCFG pCfg = (PKITL_DEV_TRANSCFG) KITLDATA(pHdr); USHORT cbData = sizeof (PpfsFmtBuf) - Kitl.FrmHdrSize - sizeof (KITL_HDR) - sizeof (KITL_DEV_TRANSCFG); if (!Kitl.pfnGetDevCfg ((LPBYTE) (pCfg+1), &cbData)) return FALSE; memset (pHdr, 0, sizeof (KITL_HDR)); pHdr->Id = KITL_ID; pHdr->Service = KITL_SVC_ADMIN; pHdr->Cmd = KITL_CMD_TRAN_CONFIG; cbData += sizeof (KITL_DEV_TRANSCFG); pCfg->wLen = cbData; pCfg->wCpuId = KITL_CPUID; memcpy (pCfg->szDevName, Kitl.szName, KITL_MAX_DEV_NAMELEN); cbData += sizeof (KITL_HDR); 注意GetDeviceConfig函数在Ether中获取了source ip, source mac和port, 而在usb serial和traditional serial中都是stub. 填写完KITL数据后,就调用KitlSendFrame了。在KitlSendFrame中又首先调用OEM层的Kitl.pfnEncode, 根据ETHER或SERIAL格式填写packet header,然后才调用KitlSendRawData, 进而用Kitl.pfnSend把数据发往PC端的PB。 下面先看Ethernet Kitl中具体发送的该数据包。 00000000: FF FF FF FF FF FF 00 05 5D 53 1C 37 08 00 45 00 00000010: 00 44 00 00 00 00 40 11 FB FE C0 A8 BE 02 FF FF 00000020: FF FF 03 D5 03 D5 00 30 01 F4 45 44 42 47 FF 00 00000030: 00 09 20 00 41 00 41 4D 4F 49 53 4F 46 54 37 32 00000040: 32 33 00 00 00 00 C0 A8 BE 02 00 05 5D 53 1C 37 00000050: 03 D5 逐位分析如下: ------------------------DLC Header 0~5 FF FF FF FF FF //Destination Mac Address. (BROADCAST) 6~11 00 05 5d 53 1c 37 //Source Mac Address (Station DLink 531C37) 12~13 08 00 // fType = IP. ( IP_Frame 08 00 | ARP_FRAME 08 06 ) -----------------------IPV4 Header 14 45 // Stardard IPV4 Header, Version =4, header length=20 bytes 15 00 // TOS ( type of service, //bit 0 = 0, CE bit - no congestion; //bit1 = 0, ECT bit - transport protocol will ignore the CE bit; //bit 2 =0, normal reliability; //bit 3 = 0, normal throughtput; //bit 4 = 0, normal delay; //bit 5 ~ bit 7 = 000, routine. 16~17 00 44 // Total length = 68 bytes. 18~19 00 00 // id 20~21 00 00 // fragment (may fragmet = 0 , last fragment = 0, fragment oFFset = 0 bytes) 22 40 // TTL (Time to live = 64 seconds/hops) 23 11 // protocol = UDP ( UDP_PROTOCOL=17 | ICMP_PROTOCOL=1 ) 24~25 FB FE // header check sum 26~29 C0 A8 BE 02 // Source Ip 192.168.190.2 30~33 FF FF FF FF // Destination Ip (it is a brocast packet) ------------------------UDP Header 34~35 03 D5 // source port = 981 36~37 03 D5 // destination port = 981 38~39 00 30 // length = 48 40~41 01 F4 // header check sum 42~82 UDP 40 bytes of data ------------------------KITL PACKET 42~45 45 44 42 47 // "EDBG" 46 FF // service = KITL_SVC_ADMIN 47 00 // Flags 48 00 // SeqNum 49 09 // Cmd = KITL_CMD_TRAN_CONFIG 50~51 20 00 // wLen 52~53 41 00 // wCPUId = KITL_CPU_ARMV4I 54~69 41 4D 4F 49 53 4F 46 54 37 32 32 33 00 00 00 00 // szDeviceName = AMOISOFT7223 70~73 C0 A8 BE 02 // Source IP = 192.168.190.2 74~79 00 05 5D 53 1C 37 // Source Mac Address (Station DLink 531C37) 80~81 03 D5 // Source Port = 981 // 最后三行是在KITLConnectToDesktop中调用Kitl.pfnGetDevCfg时加进来的. 不太理解为什么IPV4里已经包含该信息了, 这里又重复一次. 而在SerialType中SerialGetDevCfg是个Stub. 接着来看一下Traditional Serial KITL发送的数据包 [COM1, BaudRate=115200, DataBits=8, StopBits=1, Parity=None, FlowControl=None] 发送bytes=cbData + Kitl.FrmHdrSize + Kitl.FrmTlrSize = 0x1C + 0xA + 0x0 = 0x26 = 38 bytes -----------------------------SERIAL HEADER----------------------------- 0~3 6B 49 54 4C // "kITL" 4 AA // PacketType = OAL_KITL_SERIAL_PACKET 5 00 // reserved 6~7 1C 00 // PayloadSize = cbData 8 3E // crcData 9 58 // crcHeader -----------------------------KITL PACKET----------------------------- 10~13 45 44 42 47 // "EDBG" 14 FF // service = KITL_SVC_ADMIN 15 00 // flags = 0 16 00 // SeqNum = 0 17 09 // Cmd = KITL_CMD_TRAN_CONFIG 18~19 14 00 // wLen = 20 20~21 41 00 // wCPUId = KITL_CPU_ARMV4I 22~38 53 65 72 69 61 6C 44 65 76 69 63 65 00 00 00 00 00 // "SerialDevice" 下面再看看USB SERIAL KITL在这步发送的数据包, 除了DeviceName以外, 其他都和Traditional Serial的一样. 00000000: 6b 49 54 4c aa 00 1c 00 a9 c3 45 44 42 47 FF 00 00000010: 00 09 14 00 41 00 55 53 42 44 65 76 69 63 65 00 00000020: 00 00 00 00 00 00 逐位分析如下: -----------------------------SERIAL HEADER----------------------------- 0~3 6B 49 54 4C // "kITL" 4 AA // PacketType = OAL_KITL_SERIAL_PACKET 5 00 // reserved 6~7 1C 00 // PayloadSize = cbData 8 9F // crcData 9 C3 // crcHeader -----------------------------KITL PACKET----------------------------- 10~13 45 44 42 47 // "EDBG" 14 FF // service = KITL_SVC_ADMIN 15 00 // flags = 0 16 00 // SeqNum = 0 17 09 // Cmd = KITL_CMD_TRAN_CONFIG 18~19 14 00 // wLen = 20 20~21 41 00 // wCPUId = KITL_CPU_ARMV4I 22~38 55 53 42 44 65 76 69 63 65 00 00 00 00 00 00 00 // "USBDevice" 发送完成后就开始轮询等待PB回应。具体到函数就是KITLPollResponse -> KITLPollData -> HandleRecvInterrupt. 前面的箭头表示函数调用关系,而不是指针。在HandleRecvInterrupt中再调用Kitl.pfnRecv收取PACKET, 然后进到ProcessRecvFrame中处理。由于我们现在所处阶段,所以PB回应的PACKET中,必定serivce = KITL_SVC_ADMIN, 进而走到ProcessAdminMsg中处理。 Ethernet KITL收到的第一个包是这样的: 00000000: 00 05 5d 53 1c 37 00 40 b8 51 a8 32 08 00 45 00 00000010: 00 50 fe 49 00 00 80 11 3e f4 c0 a8 be 0b c0 a8 00000020: be 02 06 8e 03 d5 00 3c 4d ea 45 44 42 47 ff 00 00000030: 00 09 2c 00 00 00 0f 00 00 00 56 34 12 00 ff ff 00000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000050: ff ff ff ff bf ff ff ff bf ff ff ff ff ff 分析如下: --------------------------------DLC Header-------------------------------- 0~5 00 05 5d 53 1c 37 // Desination Mac Address = Station DLink 531C37 6~11 00 40 b8 51 a8 32 // Source Mac Address = Station IdeaAs51A832 12~13 08 00 // Ethertype = IP --------------------------------IP Header-------------------------------- 14 45 // IpVersion = 4, header length = 20 bytes 15 00 // Type of service = 00 16~17 00 50 // Total length = 80 bytes 18~19 fe 49 // Identification = 65097 20~21 00 // flags = 0, fragment offset = 0 bytes. 22 80 // Time to live = 128 seconds/hops 23 11 // Protocol = 17 (UDP) 24~25 3e f4 // Header checksum (correct) 26~29 c0 a8 be 0b // Source IP address = [192.168.190.11] 30~33 c0 a8 be 02 // Destination address = [192.168.190.2] --------------------------------UDP Header-------------------------------- 34~35 06 8e // Source port = 1678 36~37 03 d5 // Destination port = 981 38~39 00 3c // Length = 60 40~41 4d ea // Checksum 42~93 KITL PACKET // UDP 52 bytes of data --------------------------------Kitl Packet-------------------------------- 42~45 45 44 42 47 // "EDBG" 46 ff // service = KITL_SVC_ADMIN 47 00 // Flags 48 00 // SeqNum 49 09 // cmd = KITL_CMD_TRAN_CONFIG 50~51 2c 00 00 00 // dwLen 52~57 0f 00 00 00 // dwFlags = 0f 58~61 56 34 12 00 // dwKeySig = 00123456 (HOST_TRANSCFG_KEYSIG) 62~65 FF FF FF FF // g_dwKeys[0] = -1, nk , registry settings of desktop zone settings, 66~69 FF FF FF FF // g_dwKeys[1] = -1, filesys, ditto 70~73 FF FF FF FF // g_dwKeys[2] = -1, fsdmgr 74~77 FF FF FF FF // g_dwKeys[3] = -1, relfsd 78~81 FF FF FF FF // g_dwKeys[4] = -1, device 82~85 FF BF FF FF // g_dwKeys[5], CeLogZoneCE 86~89 FF BF FF FF // g_dwKeys[6], CeLogZoneUser 90~93 FF FF FF FF // g_dwKeys[7] = -1, CeLogZoneProcess 上面的关键点在于 cmd = 0x09, 这样就进入ProcessAdminMsg函数中的case KITL_CMD_TRAN_CONFIG,该分支里有KITLGlobalState |= KITL_ST_DESKTOP_CONNECTED, 打上该标记后就很容易往下执行了。 下面看看Traditional Serial在KITLPollingData里收到的第一个包: -----------------------------SERIAL HEADER----------------------------- 0~3 6B 49 54 4C // "kITL" 4 AA // PacketType = OAL_KITL_SERIAL_PACKET 5 01 // reserced 6~7 34 00 // PayloadSize = cbData 8 51 // crcData 9 84 // crcHeader --------------------------------Kitl Packet-------------------------------- 42~45 45 44 42 47 // "EDBG" 46 FF // service = KITL_SVC_ADMIN 47 00 // Flags 48 00 // SeqNum 49 09 // cmd = KITL_CMD_TRAN_CONFIG 50~51 2C 00 00 00 // dwLen 52~57 0F 00 00 00 // dwFlags = 0F 58~61 56 34 12 00 // dwKeySig = 00123456 (HOST_TRANSCFG_KEYSIG) 62~93 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff bf ff ff ff bf ff ff ff ff ff // g_dwKeys[0]~[7] 可以看到,除去Kitl类型决定的Header外, 这个包的Kitl Packe的内容是一样的. Cmd=0x9和dwKeySig=00123456决定了能够使KITLGlobalState |= KITL_ST_DESKTOP_CONNECTED. 但目前Traditional Serial Kitl的问题是在打上CONNECTED记号后,会继续运行HandleRecvInterrupt函数, 只有当fFrameRecvd不为零, 即该次循环没有收到packet的时候, 才会跳出这个while循环以跳出该函数, 继续往下执行完成StartKitl. 但从串口监视的数据来看,PB在发cmd=0x9这个PACKET后,还不断地发送cmd=0x6和cmd=0xA的packet, 使得程序卡在这里. 值得一提的时, 这个cmd=0x9的包也不是每次都能收到的, 有时候(满足一定条件或概率, 条件未知)在发送cmd=0x9的包后, 将只收到0x6和0xa的包. 另外, 从串口KITL监听的数据来看, 从点下AttachDevice开始download image开始, PB就发kITL数据包过来了. 如果开启监听的话, 可以看到在PB收到cmd=0x9之前, 全部是往TARGET发送0x6和0xA的包, 如下: 设置 RTS. 写串口 18 bytes: 6b 49 54 4c aa 01 08 00 1b 22 45 44 42 47 ff 00 00 0a 清除 RTS. 设置 RTS. 写串口 42 bytes: 6b 49 54 4c aa 01 20 00 7e 9d 45 44 42 47 ff 00 00 06 01 44 42 47 4d 53 47 00 2c ff 91 08 28 9c 03 00 90 ff 91 08 00 ff 00 00 清除 RTS. 设置 RTS. 写串口 42 bytes: 6b 49 54 4c aa 01 20 00 4c 6b 45 44 42 47 ff 00 00 06 01 50 50 53 48 00 47 00 2c ff 91 08 28 9c 03 00 90 ff 91 08 00 ff 00 00 清除 RTS. 当然如果没有开启串口监听, 即没有从相应的PORT上面读取数据, 那么我觉得应该在TARGET完成UART初始化并接收第一个PACKET之前, PORT上面一直停留在PB发送的第一个包上. 中间遇到个事情。当我失误先在其他WINXP应用程序里打开COM1,然后AttachDevice的时候(PB里设的Serial COM1 KITL), PB里的DebugWindow直接出现了这三行 (CoreCon) 16:54:33 04/18/2005 中国标准时间: Failed to connect debug message service! Please check the transport settings. (CoreCon) 16:54:33 04/18/2005 中国标准时间: Transport service failed to connect (CoreCon) 16:54:33 04/18/2005 中国标准时间: Warning: One or more services failed to connect. Make sure that the service is properly configured. 这和用PB for Wince5.0里使用USB KITL然后Attach时的显示是完全一样的。 还有我怀疑DeviceName也不是随便起的. 我使用Serial Kitl时, 给pszDeviceID="FFUART", 而连接后在PC的注册表里 [HKEY_CURRENT_USER / Software / Microsoft / Windows CE Tools / Platform Manager] 里面和DeviceName=AMOISOFT7223并列的下一个项里键值DeviceName=SerialDevice. 而用USB连接时这个键值为USBDevice USB SERIAL KITL收到的第一个包是这样的 00000000: 6b 49 54 4c aa 05 20 00 4f 72 45 44 42 47 ff 00 00000010: 00 06 01 44 42 47 4d 53 47 00 2c ff 5e 08 28 d3 00000020: 03 00 90 ff 5e 08 00 ff 00 00 分析如下: -----------------------------SERIAL HEADER----------------------------- 0~3 6B 49 54 4C // "kITL" 4 AA // PacketType = OAL_KITL_SERIAL_PACKET 5 05 // reserced 6~7 20 00 // PayloadSize = cbData 8 4F // crcData 9 72 // crcHeader -----------------------------KITL PACKET----------------------------- 10~13 45 44 42 47 // “kITL" 14 FF // service = KITL_SVC_ADMIN 15 00 // flags 16 00 // SeqNum 17 06 // cmd = KITL_CMD_SVC_CONFIG 18 01 // pCfg.ProtocolVersion = 1 19~24 44 42 47 4d 53 47 00 // ServiceName = "DBGMSG" + "/0" 25 2c // ServiceID 26 ff // WindowSize 27 5e // flags 28~ // 未知 如果用前面Traditional Serial串口监听的依据来看, PB只是例常性地循环发送0xA,0x6,0x6三个包而已, 并没有对我们发过去的0x9包作出响应. 关键点在于cmd = 0x6 (KITL_CMD_SVC_CONFIG), 这和上面ETHERNET及FFUART收到的CMD是不同的,这将导致ProcessAdminMsg进入不同的分支。而KITL_CMD_SVC_CONFIG这个分支感觉是Passive Kitl才会应该进来的, 在走到这步之前KITLClients[i]->State应该为KITL_CLIENT_REGISTERING状态,否则就当状态出错处理。而我们的Active Kitl即使是已经调通的Ethernet, 走到这里时也没有REGISTERING或REGISTERED状态。 USB SERIAL KITL就夭折于此地。 |