观's profileTo the world,you may jus...PhotosBlogListsMore ![]() | Help |
|
21/11/2009 开发杂记一忙起来又有两个星期没有更新space了,麻烦的事情真的太多,nandflash分区还没搞定,那篇“下”都不知道什么时候发表了,往后拖拖吧。上个星期将产品的话逻辑整理了下,同时也解决了几个程序的bug,但是发现一个新的问题就是画图的速度比较慢,还是需要想办法解决这个问题。这个星期整理了下电源管理的资料,准备搞定电源管理,不过也很不容易,毕竟没有真正意义上的电源管理芯片,同时要做好功耗还是个难题。这些问题是从老大的原理图开始的,之前没有任何的沟通就直接改了,现在又要求这样低的功耗,真的是没有什么好的办法,尽力而为了!昨天又抽空将SD卡的问题解决了,真的不明白为什么要有这样的开发板公司,SD1和SD2竟然不能同时使用,初期为什么就不解决这样的问题,唉!现在修改了硬件之后两个SDIO接口都可以使用了,目前还没有发现什么问题,但是有点担心SD2的读写存在问题,先看看吧。最近加了个群,找到了些快速编译的方法,做个记录吧,挺实用的,以前浪费在这个上面太多的时间了。快速编译的前提是先整体的编译一次,当其他情况可以按照以下方法去编译:
以上都是关于快速编译的一些技巧,同时PB的Build OS菜单有一些不同的编译选项,也记录下这些选项的功能吧。
了解了这些之后大大的节省了编译的时间,本来沉浸在编译的痛苦之中的,这下可以解放出来了。 06/11/2009 飞思卡尔MX27+andflsh+wince5.0上的HIVE注册表实现(上)今天整了一天的HIVE注册表的实现,发现这个和Flash的分区联系非常紧密。和官方中的说明比起来就显得非常的复杂了,下面来说下如何建立HIVE的具体操作:官方的操作说明十分简单,总共分六步:
以上就是官方建立HIVE注册表的步骤了,可是实际操作远远没有这么简单。 2009-11-06 10:35 在自己项目的平台上折腾了两天了,今天才恍然大悟,改动了eboot却没有将eboot烧到板子上,真是失策。现在板子又出问题了,真是祸不单行。 2009-11-06 15:38 问题终于解决,是串口板的问题,换了块串口板就可以烧eboot了。可是又有新的问题出现了,eboot烧了进去之后跑不起来。我的天啊!现在问题找到了,浪费了大把的时间。具体问题记录下来:
通过更改eboot目前可以将整个flash分为三个分区了:part00(binfs),part001(fatfs),part03(boot)但是可惜的是fat分区还是没有挂起,明天来搞挂起吧,希望不要这么曲折了。 04/11/2009 NandFlash的分区实现提到分区就需要知道MBR,了解分区表。什么是MBR硬盘的0柱面、0磁头、1扇区称为主引导扇区,NANDFLASH由BLOCK和Sector组成,所以NANDFLASH的第0 BLOCK,第1 Sector为主引导扇区,FDISK程序写到该扇区的内容称为主引导记录(MBR)。该记录占用512个字节,它用于硬盘启动时将系统控制权交给用户指定的,并在分区表中登记了的某个操作系统区。 MBR的组成 一个扇区的硬盘主引导记录MBR由如图6-15所示的4个部分组成。
MBR中的分区信息结构 占用512个字节的MBR中,偏移地址01BEH--01FDH的64个字节,为4个分区项内容(分区信息表)。它是由磁盘介质类型及用户在使用 FDISK定义分区说确定的。在实际应用中,FDISK对一个磁盘划分的主分区可少于4个,但最多不超过4个。每个分区表的项目是16个字节,其内容含义 如表6-19所示。
EBOOT中对NAND分区主要代码,eboot目录下的fmd.cpp文件,与NAND驱动基本相同,所以,要对NAND进行分区,就得对NAND驱动非常熟悉。透彻了解。然后就是E:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BOOTPART\bootpart.cpp文件了。该文件主要通过调用NANDFLASH的读写操作来写入MBR,也是今天主要的分析对象。
主要函数。/* BP_OpenPartition** Opens/creates a partition depending on the creation flags. If it is opening* and the partition has already been opened, then it returns a handle to the* opened partition. Otherwise, it loads the state information of that partition* into memory and returns a handle.** ENTRY* dwStartSector - Logical sector to start the partition. NEXT_FREE_LOC if none* specified. Ignored if opening existing partition.* dwNumSectors - Number of logical sectors of the partition. USE_REMAINING_SPACE* to indicate to take up the rest of the space on the flash for that partition (should* only be used when creating extended partitions). This parameter is ignored* if opening existing partition.* dwPartType - Type of partition to create/open.* fActive - TRUE indicates to create/open the active partition. FALSE for* inactive.* dwCreationFlags - PART_CREATE_NEW to create only. Fail if it already* exists. PART_OPEN_EXISTING to open only. Fail if it doesn't exist.* PART_OPEN_ALWAYS creates if it does not exist and opens if it* does exist.** EXIT* Handle to the partition on success. INVALID_HANDLE_VALUE on error.*/
HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)(注:示例代码为本人EBOOT中分区实现源码(WINCE5.0+S3C2440+128MNAND,MBR写在第4个BLOCK,分一个BINFS格式分区和一个FAT格式分区)。)BOOL WriteRegionsToBootMedia(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr)在把SDRAM中的NK烧写到NAND中去之前,先创建一个BINFS分区。hPart = BP_OpenPartition( (NK_START_BLOCK+1)*PAGES_PER_BLOCK, // next block of MBR BINFS_BLOCK*PAGES_PER_BLOCK,//SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength))*PAGES_PER_BLOCK, //align to blockPART_BINFS,TRUE,PART_OPEN_ALWAYS);第一个参数分区的起始sector 为(NK_START_BLOCK+1)*PAGES_PER_BLOCK,第二个参数分区的结束 sector为BINFS_BLOCK*PAGES_PER_BLOCK,第三个参数分区的格式为PART_BINFS,即BINFS格式,第四个参数指示该分区为活动分区,fActive = TURE,第五个参数PART_OPEN_ALWAYS指示如果分区不存在就创建该分区,存在就OPEN该分区,返回分区句柄。HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags){DWORD dwPartIndex;BOOL fExists;ASSERT (g_pbMBRSector);if (!IsValidMBR()) {DWORD dwFlags = 0;//flyRETAILMSG(1, (TEXT("BP_OpenPartition:: dwStartSector=0x%x ,dwNumSectors= 0x%x.,dwPartType = 0x%x\r\n"), dwStartSector, dwNumSectors,dwPartType));if (dwCreationFlags == PART_OPEN_EXISTING) {RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR. Cannot open existing partition 0x%x.\r\n"), dwPartType));return INVALID_HANDLE_VALUE;}RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR. Formatting flash.\r\n")));if (g_FlashInfo.flashType == NOR) {dwFlags |= FORMAT_SKIP_BLOCK_CHECK;}//flyRETAILMSG(1, (TEXT("BP_LowLevelFormat: g_pbMBRSector=0x%x, g_dwMBRSectorNum= 0x%x.\r\n"), *g_pbMBRSector, g_dwMBRSectorNum));BP_LowLevelFormat (SECTOR_TO_BLOCK(dwStartSector), SECTOR_TO_BLOCK(dwNumSectors), dwFlags);dwPartIndex = 0;fExists = FALSE;}else {fExists = GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);}RETAILMSG(1, (TEXT("OpenPartition: Partition Exists=0x%x for part 0x%x.\r\n"), fExists, dwPartType));if (fExists) {// Partition was found.if (dwCreationFlags == PART_CREATE_NEW)return INVALID_HANDLE_VALUE;if (g_partStateTable[dwPartIndex].pPartEntry == NULL) {// Open partition. If this is the boot section partition, then file pointer starts after MBRg_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);g_partStateTable[dwPartIndex].dwDataPointer = 0;}if ( dwNumSectors > g_partStateTable[dwPartIndex].pPartEntry->Part_TotalSectors )return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);elsereturn (HANDLE)&g_partStateTable[dwPartIndex];}else {// If there are already 4 partitions, or creation flag specified OPEN_EXISTING, fail.if ((dwPartIndex == NUM_PARTS) || (dwCreationFlags == PART_OPEN_EXISTING))return INVALID_HANDLE_VALUE;// Create new partitionreturn CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);}return INVALID_HANDLE_VALUE;}进入函数,首先做的事就是检测MBR的有效性。通过函数IsValidMBR()实现。检测MBR的有效性,首先要知道MBR保存在哪里,前面说过NANDFLASH的第0 BLOCK,第1 Sector为主引导扇区,也就是MBR,但是NAND如果被当作启动芯片,○地址一般被BOOTLOADER代码占据,MBR只有放在后面的BLOCK中。所以我把第0 个BLOCK放NBOOT,第1个BLOCK放TOC,第2个BLOCK放EBOOT,第3个BLOCK保留,第4个BLOCK就放MBR。static BOOL IsValidMBR(){// Check to see if the MBR is valid// MBR block is always located at logical sector 0g_dwMBRSectorNum = GetMBRSectorNum();RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x\r\n"), g_dwMBRSectorNum));if ((g_dwMBRSectorNum == INVALID_ADDR) || !FMD_ReadSector (g_dwMBRSectorNum, g_pbMBRSector, NULL, 1)) {RETAILMSG (1, (TEXT("IsValidMBR-----return FALSE-------------------\r\n")));return FALSE;}return ((g_pbMBRSector[0] == 0xE9) &&(g_pbMBRSector[1] == 0xfd) &&(g_pbMBRSector[2] == 0xff) &&(g_pbMBRSector[SECTOR_SIZE_FS-2] == 0x55) &&(g_pbMBRSector[SECTOR_SIZE_FS-1] == 0xAA));}IsValidMBR()实现的第一行就是给全局变量g_dwMBRSectorNum 赋值,显而易见,g_dwMBRSectorNum就是指示保存MBR的那个Sector了。g_dwMBRSectorNum = GetMBRSectorNum(); //是获得保存MBR的那个Sectorstatic DWORD GetMBRSectorNum (){DWORD dwBlockNum = 3, dwSector = 0;SectorInfo si;while (dwBlockNum < g_FlashInfo.dwNumBlocks) {if (!IS_BLOCK_UNUSABLE (dwBlockNum)) {dwSector = dwBlockNum * g_FlashInfo.wSectorsPerBlock;if (!FMD_ReadSector (dwSector, NULL, &si, 1)) {RETAILMSG(1, (TEXT("GetMBRSectorNum: Could not read sector 0x%x.\r\n"), dwSector));return INVALID_ADDR;}// Check to see if logical sector number is 0if (si.dwReserved1 == 0) {//RETAILMSG(1,(TEXT("dwBlockNum=%d\r\n"),dwBlockNum));return dwSector;}}dwBlockNum++;}return INVALID_ADDR;}这里dwBlockNum直接给了个3,因为NBOOT,TOC,EBOOT已经把前三个BLOCK用了。所以MBR的选择直接排除了前三个BLOCK了。#define IS_BLOCK_UNUSABLE(blockID) ((FMD_GetBlockStatus (blockID) & (BLOCK_STATUS_BAD|BLOCK_STATUS_RESERVED)) > 0)然后确定BLOCK是否可使用的BLOCK,最后通si.dwReserved1 == 0来判断是不是选择这个Sector来保存MBR。IsValidMBR()中还有一个重要的结构就是g_pbMBRSector数组,它就是MBR了。函数返回时,MBR必须符合下列记录。return ((g_pbMBRSector[0] == 0xE9) &&(g_pbMBRSector[1] == 0xfd) &&(g_pbMBRSector[2] == 0xff) &&(g_pbMBRSector[SECTOR_SIZE_FS-2] == 0x55) &&(g_pbMBRSector[SECTOR_SIZE_FS-1] == 0xAA));可以看到只有开始三个字节为0XE9,FD,FF,当然,还有熟悉的结束标志符0X55AA。如果没有检测到MBR,则先对NANDFLASH进行低级格式化。BP_LowLevelFormat (SECTOR_TO_BLOCK(dwStartSector), SECTOR_TO_BLOCK(dwNumSectors), dwFlags);再创建分区,CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);。BOOL BP_LowLevelFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags){dwNumBlocks = min (dwNumBlocks, g_FlashInfo.dwNumBlocks);RETAILMSG(1,(TEXT("fly::Enter LowLevelFormat [0x%x, 0x%x].\r\n"), dwStartBlock,dwNumBlocks));// dwStartBlock + dwNumBlocks - 1));// Erase all the flash blocks.if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))return(FALSE);// Determine first good starting blockwhile (IS_BLOCK_UNUSABLE (dwStartBlock) && dwStartBlock < g_FlashInfo.dwNumBlocks) {dwStartBlock++;}if (dwStartBlock >= g_FlashInfo.dwNumBlocks) {RETAILMSG(1,(TEXT("BP_LowLevelFormat: no good blocks\r\n")));return FALSE;}// MBR goes in the first sector of the starting block. This will be logical sector 0.g_dwMBRSectorNum = dwStartBlock * g_FlashInfo.wSectorsPerBlock;RETAILMSG(1,(TEXT("fly:g_dwMBRSectorNum=%d\r\n"),g_dwMBRSectorNum));// Create an MBR.CreateMBR();return(TRUE);}在对NANDFLASH进行低格时,主要对坏块的处理。if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))检测每一个Sector,每个BLOCK只要有一个Sector不能读写这个块都会被处理成坏块,这样才能保证系统的稳定性。在函数的最后调用了 CreateMBR();来创建一个MBR。static BOOL CreateMBR(){// This, plus a valid partition table, is all the CE partition manager needs to recognize// the MBR as valid. It does not contain boot code.memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);g_pbMBRSector[0] = 0xE9;g_pbMBRSector[1] = 0xfd;g_pbMBRSector[2] = 0xff;g_pbMBRSector[SECTOR_SIZE_FS-2] = 0x55;g_pbMBRSector[SECTOR_SIZE_FS-1] = 0xAA;// Zero out partition table so that mspart treats entries as empty.memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);return WriteMBR();}当然。因为还没有进行分区,这里写入的MBR分区表部分是空的。static BOOL WriteMBR(){DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;//dwMBRBlockNum = 1 ;RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x,g_dwMBRSectorNum = 0x%x.\r\n"), dwMBRBlockNum,g_dwMBRSectorNum));memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);// No need to check return, since a failed read means data hasn't been written yet.ReadBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf);if (!FMD_EraseBlock (dwMBRBlockNum)) {RETAILMSG (1, (TEXT("CreatePartition: error erasing block 0x%x\r\n"), dwMBRBlockNum));return FALSE;}memcpy (g_pbBlock + (g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock) * g_FlashInfo.wDataBytesPerSector, g_pbMBRSector, g_FlashInfo.wDataBytesPerSector);g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;g_pSectorInfoBuf->dwReserved1 = 0;RETAILMSG(1, (TEXT("fly::WriteMBR: MBR block = 0x%x.\r\n"), dwMBRBlockNum));if (!WriteBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf)) {RETAILMSG (1, (TEXT("CreatePartition: could not write to block 0x%x\r\n"), dwMBRBlockNum));return FALSE;}return TRUE;}在WriteMBR()函数中,就写入了判断MBR 的一些标志到BLOCK, g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;g_pSectorInfoBuf->dwReserved1 = 0;Wince系统启动时,具体是NANDFLASH驱动加载成功后,MOUNT文件系统到NANDFLASH之前,也会通过读取这些SectorInfo来得到MBR 保存的BLOCK,进而读取MBR,获得分区信息,从而把各分区MOUNT到相应文件系统。格式化完成,MBR也写入成功后就可以开始新建分区了。/* CreatePartition** Creates a new partition. If it is a boot section partition, then it formats* flash.** ENTRY* dwStartSector - Logical sector to start the partition. NEXT_FREE_LOC if* none specified.* dwNumSectors - Number of logical sectors of the partition. USE_REMAINING_SPACE* to indicate to take up the rest of the space on the flash for that partition.* dwPartType - Type of partition to create.* fActive - TRUE indicates to create the active partition. FALSE for* inactive.* dwPartIndex - Index of the partition entry on the MBR** EXIT* Handle to the partition on success. INVALID_HANDLE_VALUE on error.*/static HANDLE CreatePartition (DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwPartIndex){DWORD dwBootInd = 0;RETAILMSG(1, (TEXT("CreatePartition: Enter CreatePartition for 0x%x.\r\n"), dwPartType));if (fActive)dwBootInd |= PART_IND_ACTIVE;if (dwPartType == PART_BOOTSECTION || dwPartType == PART_BINFS || dwPartType == PART_XIP)dwBootInd |= PART_IND_READ_ONLY;// If start sector is invalid, it means find next free sectorif (dwStartSector == NEXT_FREE_LOC) {dwStartSector = FindFreeSector();if (dwStartSector == INVALID_ADDR) {RETAILMSG(1, (TEXT("CreatePartition: can't find free sector.\r\n")));return INVALID_HANDLE_VALUE;}// Start extended partition on a block boundaryif ((dwPartType == PART_EXTENDED) && (dwStartSector % g_FlashInfo.wSectorsPerBlock)) {dwStartSector = (dwStartSector / g_FlashInfo.wSectorsPerBlock + 1) * g_FlashInfo.wSectorsPerBlock;}}// If num sectors is invalid, fill the rest of the space upif (dwNumSectors == USE_REMAINING_SPACE) {DWORD dwLastLogSector = LastLogSector();if (dwLastLogSector == INVALID_ADDR)return INVALID_HANDLE_VALUE;// Determine the number of blocks to reserve for the FAL compaction when creating an extended partition.DWORD dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE;if((dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE) < MINIMUM_FLASH_BLOCKS_TO_RESERVE) {dwReservedBlocks = MINIMUM_FLASH_BLOCKS_TO_RESERVE;}dwNumSectors = dwLastLogSector - dwStartSector + 1 - dwReservedBlocks * g_FlashInfo.wSectorsPerBlock;}if (!AreSectorsFree (dwStartSector, dwNumSectors)){RETAILMSG (1, (TEXT("fly:::::CreatePartition: sectors [0x%x, 0x%x] requested are out of range or taken by another partition\r\n"), dwStartSector, dwNumSectors));return INVALID_HANDLE_VALUE;}RETAILMSG(1, (TEXT("CreatePartition: Start = 0x%x, Num = 0x%x.\r\n"), dwStartSector, dwNumSectors));AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);if (dwBootInd & PART_IND_READ_ONLY) {if (!WriteLogicalNumbers (dwStartSector, dwNumSectors, TRUE)) {RETAILMSG(1, (TEXT("CreatePartition: can't mark sector info.\r\n")));return INVALID_HANDLE_VALUE;}}if (!WriteMBR())return INVALID_HANDLE_VALUE;g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);g_partStateTable[dwPartIndex].dwDataPointer = 0;return (HANDLE)&g_partStateTable[dwPartIndex];}如果第二个参数为-1,则视为将余下的所有空间划为一个分区。LastLogSector();函数获得最后一个逻辑Sector。static DWORD LastLogSector(){if (g_dwLastLogSector) {return g_dwLastLogSector;}DWORD dwMBRBlock = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;DWORD dwUnusableBlocks = dwMBRBlock;for (DWORD i = dwMBRBlock; i < g_FlashInfo.dwNumBlocks; i++) {if (IS_BLOCK_UNUSABLE (i))dwUnusableBlocks++;}g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;RETAILMSG(1, (TEXT("fly:::LastLogSector: Last log sector is: 0x%x.\r\n"), g_dwLastLogSector));return g_dwLastLogSector;}即g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;//(NAND 的BLOCK总数 – MBR保存的那个BLOCK)* 每个BLOCK的Sector数 – 保存MBR的那个Sector。得到的就是从MBR那个Sector之后的所有Sector,即逻辑大小。AreSectorsFree (dwStartSector, dwNumSectors)函数判断参数提供的起始Sector和个数有没有超出来NAND的界限,或者逻辑分区的界限。重头戏开始了。通过AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd); 准备分区信息写入分区表。/* AddPartitionTableEntry** Generates the partition entry for the partition table and copies the entry* into the MBR that is stored in memory.*** ENTRY* entry - index into partition table* startSector - starting logical sector* totalSectors - total logical sectors* fileSystem - type of partition* bootInd - byte in partition entry that stores various flags such as* active and read-only status.** EXIT*/static void AddPartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd){PARTENTRY partentry = {0};Addr startAddr;Addr endAddr;ASSERT(entry < 4);// no checking with disk info and start/total sectors because we allow// bogus partitions for testing purposes// initially known partition table entrypartentry.Part_BootInd = bootInd;partentry.Part_FileSystem = fileSystem;partentry.Part_StartSector = startSector;partentry.Part_TotalSectors = totalSectors;// logical block addresses for the first and final sector (start on the second head)startAddr.type = LBA;startAddr.lba = partentry.Part_StartSector;endAddr.type = LBA;endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;// translate the LBA addresses to CHS addressesstartAddr = LBAtoCHS(&g_FlashInfo, startAddr);endAddr = LBAtoCHS(&g_FlashInfo, endAddr);// starting addresspartentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);// lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));// ending address:partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);// lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));memcpy(g_pbMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));}这里面的地址信息是一种叫CHS(Cyinder/Head/Sector)的地址。eboot中有将逻辑地址LBS(Logical Block Addr)与这种地址互相转换的函数LBAtoCHS,CHSToLBA。Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba){Addr chs;DWORD tmp = pFlashInfo->dwNumBlocks * pFlashInfo->wSectorsPerBlock;chs.type = CHS;chs.chs.cylinder = (WORD)(lba.lba / tmp); // 柱面,应该始终是0tmp = lba.lba % tmp;chs.chs.head = (WORD)(tmp / pFlashInfo->wSectorsPerBlock); // 块地址chs.chs.sector = (WORD)((tmp % pFlashInfo->wSectorsPerBlock) + 1); // 扇区+1return chs;}Addr CHStoLBA(FlashInfo *pFlashInfo, Addr chs){Addr lba;lba.type = LBA;lba.lba = ((chs.chs.cylinder * pFlashInfo->dwNumBlocks + chs.chs.head)* pFlashInfo->wSectorsPerBlock)+ chs.chs.sector - 1;return lba;}如果分区的格式有只读属性,则通过WriteLogicalNumbers()函数写分区的Sectorinfo,把这部分空间保护起来。static BOOL WriteLogicalNumbers (DWORD dwStartSector, DWORD dwNumSectors, BOOL fReadOnly){DWORD dwNumSectorsWritten = 0;DWORD dwPhysSector = Log2Phys (dwStartSector);DWORD dwBlockNum = dwPhysSector / g_FlashInfo.wSectorsPerBlock;DWORD dwOffset = dwPhysSector % g_FlashInfo.wSectorsPerBlock;while (dwNumSectorsWritten < dwNumSectors) {// If bad block, move to the next blockif (IS_BLOCK_UNUSABLE (dwBlockNum)) {dwBlockNum++;continue;}memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);// No need to check return, since a failed read means data hasn't been written yet.ReadBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf);if (!FMD_EraseBlock (dwBlockNum)) {return FALSE;}DWORD dwSectorsToWrite = g_FlashInfo.wSectorsPerBlock - dwOffset;PSectorInfo pSectorInfo = g_pSectorInfoBuf + dwOffset;// If this is the last block, then calculate sectors to write if there isn't a full block to updateif ((dwSectorsToWrite + dwNumSectorsWritten) > dwNumSectors)dwSectorsToWrite = dwNumSectors - dwNumSectorsWritten;for (DWORD iSector = 0; iSector < dwSectorsToWrite; iSector++, pSectorInfo++, dwNumSectorsWritten++) {// Assert read only by setting bit to 0 to prevent wear-leveling by FALif (fReadOnly)pSectorInfo->bOEMReserved &= ~OEM_BLOCK_READONLY;// Set to write completed so FAL can map the sectorpSectorInfo->wReserved2 &= ~SECTOR_WRITE_COMPLETED;// Write the logical sector numberpSectorInfo->dwReserved1 = dwStartSector + dwNumSectorsWritten;}if (!WriteBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf))return FALSE;dwOffset = 0;dwBlockNum++;}return TRUE;}这就是为什么系统启动后,我们无法写入文件的BINFS文件系统格式分区的原因了。而FAT格式就可以。最后调用WriteMBR()完全MBR的写入,分区完毕。让我们继续回到BP_OpenPartition函数中,如果从一开始IsValidMBR()就检测到有效的MBR,GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);获得分区表。和dwPartIndex分区表的索引号。static BOOL GetPartitionTableIndex (DWORD dwPartType, BOOL fActive, PDWORD pdwIndex){PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);DWORD iEntry = 0;for (iEntry = 0; iEntry < NUM_PARTS; iEntry++, pPartEntry++) {if ((pPartEntry->Part_FileSystem == dwPartType) && (((pPartEntry->Part_BootInd & PART_IND_ACTIVE) != 0) == fActive)) {*pdwIndex = iEntry;return TRUE;}if (!IsValidPart (pPartEntry)) {*pdwIndex = iEntry;return FALSE;}}return FALSE;}重要结构:PARTENTRY// end of master boot record contains 4 partition entriestypedef struct _PARTENTRY {BYTE Part_BootInd; // If 80h means this is boot partitionBYTE Part_FirstHead; // Partition starting head based 0BYTE Part_FirstSector; // Partition starting sector based 1BYTE Part_FirstTrack; // Partition starting track based 0BYTE Part_FileSystem; // Partition type signature fieldBYTE Part_LastHead; // Partition ending head based 0BYTE Part_LastSector; // Partition ending sector based 1BYTE Part_LastTrack; // Partition ending track based 0DWORD Part_StartSector; // Logical starting sector based 0DWORD Part_TotalSectors; // Total logical sectors in partition} PARTENTRY;分区表就是通过这个结构写入MBR,起始地址,分区大小,分区格式,对应结构写入MBR所在的Sector就可以了。在检测有效分区时static BOOL IsValidPart (PPARTENTRY pPartEntry){return (pPartEntry->Part_FileSystem != 0xff) && (pPartEntry->Part_FileSystem != 0);}就是通过对分区表文件系统格式的判断了。把NAND后面的空间,全部分为一个FAT格式的分区。//// create extended partition in whatever is left//hPartEx = BP_OpenPartition( (NK_START_BLOCK+1+BINFS_BLOCK) * PAGES_PER_BLOCK,NEXT_FREE_LOC, // (1024 - (NK_START_BLOCK+1+SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength)))) * PAGES_PER_BLOCK,PART_DOS32,TRUE,PART_OPEN_ALWAYS);if (hPartEx == INVALID_HANDLE_VALUE ){EdbgOutputDebugString("*** WARN: StoreImageToBootMedia: Failed to open/create Extended partition ***\r\n");}03/11/2009 SOCKET模型之重叠I/O最近的项目中有WIFI模块来和其他设备进行音视频的通信,在网络编程中发现有很多东西需要学习,所以就想记录下来。整合了网上的一些文章。 目录:
一. 重叠模型的优点
二. 重叠模型的基本原理 说了这么多的好处,你一定也跃跃欲试了吧,不过我们还是要先提一下重叠模型的基本原理。概括一点说,重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求。针对这些提交的请求,在它们完成之后,应用程序会收到通知,于是就可以通过自己另外的代码来处理这些数据了。需要注意的是,有两个方法可以用来管理重叠IO请求的完成情况(就是说接到重叠操作完成的通知):
而本文只是讲述如何来使用事件通知的的方法实现重叠IO模型,完成例程的方法准备放到下一篇讲 :) (内容太多了,一篇写不完啊) ,如没有特殊说明,本文的重叠模型默认就是指的基于事件通知的重叠模型。既然是基于事件通知,就要求将Windows事件对象与WSAOVERLAPPED结构关联在一起(WSAOVERLAPPED结构中专门有对应的参数),通俗一点讲,就是。。。。对了,忘了说了,既然要使用重叠结构,我们常用的send, sendto, recv, recvfrom也都要被WSASend, WSASendto, WSARecv, WSARecvFrom替换掉了, 它们的用法我后面会讲到,这里只需要注意一点,它们的参数中都有一个Overlapped参数,我们可以假设是把我们的WSARecv这样的操作操作“绑定”到这个重叠结构上,提交一个请求,其他的事情就交给重叠结构去操心,而其中重叠结构又要与Windows的事件对象“绑定”在一起,这样我们调用完WSARecv以后就可以“坐享其成”,等到重叠操作完成以后,自然会有与之对应的事件来通知我们操作完成,然后我们就可以来根据重叠操作的结果取得我们想要的数据了。 三. 关于重叠模型的基础知识 下面来介绍并举例说明一下编写重叠模型的程序中将会使用到的几个关键函数。 1. WSAOVERLAPPED结构 这个结构自然是重叠模型里的核心,它是这么定义的typedef struct _WSAOVERLAPPED {DWORD Internal;DWORD InternalHigh;DWORD Offset;DWORD OffsetHigh;WSAEVENT hEvent; // 唯一需要关注的参数,用来关联WSAEvent对象} WSAOVERLAPPED, *LPWSAOVERLAPPED;我们需要把WSARecv等操作投递到一个重叠结构上,而我们又需要一个与重叠结构“绑定”在一起的事件对象来通知我们操作的完成,看到了和hEvent参数,不用我说你们也该知道如何来来把事件对象绑定到重叠结构上吧?大致如下:WSAEVENT event; // 定义事件WSAOVERLAPPED AcceptOverlapped ; // 定义重叠结构event = WSACreateEvent(); // 建立一个事件对象句柄ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED)); // 初始化重叠结构AcceptOverlapped.hEvent = event; // Done !!2. WSARecv系列函数
在重叠模型中,接收数据就要靠它了,它的参数也比recv要多,因为要用刀重叠结构嘛,它是这样定义的:int WSARecv(SOCKET s, // 当然是投递这个操作的套接字LPWSABUF lpBuffers, // 接收缓冲区,与Recv函数不同,这里需要一个由WSABUF结构构成的数组DWORD dwBufferCount, // 数组中WSABUF结构的数量LPDWORD lpNumberOfBytesRecvd, // 如果接收操作立即完成,这里会返回函数调用所接收到的字节数LPDWORD lpFlags, // 说来话长了,我们这里设置为0 即可LPWSAOVERLAPPED lpOverlapped, // “绑定”的重叠结构LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 完成例程中将会用到的参数,我们这里设置为 NULL);返回值:WSA_IO_PENDING : 最常见的返回值,这是说明我们的WSARecv操作成功了,但是I/O操作还没有完成,所以我们就需要绑定一个事件来通知我们操作何时完成举个例子:(变量的定义顺序和上面的说明的顺序是对应的,下同)SOCKET s;WSABUF DataBuf; // 定义WSABUF结构的缓冲区,初始化一下DataBuf#define DATA_BUFSIZE 5096char buffer[DATA_BUFSIZE];ZeroMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer;DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;
// 建立需要的重叠结构WSAOVERLAPPED AcceptOverlapped ;// 如果要处理多个操作,这里当然需要一个WSAOVERLAPPED数组WSAEVENT event; // 如果要多个事件,这里当然也需要一个WSAEVENT数组。需要注意的是可能一个SOCKET同时会有一个以上的重叠请求,也就会对应一个以上的WSAEVENTEvent = WSACreateEvent();ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));AcceptOverlapped.hEvent = event; // 关键的一步,把事件句柄“绑定”到重叠结构上作了这么多工作,终于可以使用WSARecv来把我们的请求投递到重叠结构上了,呼。。。。WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes,&Flags, &AcceptOverlapped, NULL);其他的函数我这里就不一一介绍了,因为我们毕竟还有MSDN这么个好帮手,而且在讲后面的完成例程和完成端口的时候我还会讲到一些 ^_^3. WSAWaitForMultipleEvents 函数
熟悉WSAEventSelect模型的朋友对这个函数肯定不会陌生,不对,其实大家都不应该陌生,这个函数与线程中常用的WaitForMultipleObjects函数有些地方还是比较像的,因为都是在等待某个事件的触发嘛。因为我们需要事件来通知我们重叠操作的完成,所以自然需要这个等待事件的函数与之配套。DWORD WSAWaitForMultipleEvents(DWORD cEvents, // 等候事件的总数量const WSAEVENT* lphEvents, // 事件数组的指针BOOL fWaitAll, // 这个要多说两句:// 如果设置为 TRUE,则事件数组中所有事件被传信的时候函数才会返回// FALSE则任何一个事件被传信函数都要返回// 我们这里肯定是要设置为FALSE的DWORD dwTimeout, // 超时时间,如果超时,函数会返回 WSA_WAIT_TIMEOUT// 如果设置为0,函数会立即返回// 如果设置为 WSA_INFINITE只有在某一个事件被传信后才会返回// 在这里不建议设置为WSA_INFINITE,因为。。。后面再讲吧..-_-bBOOL fAlertable // 在完成例程中会用到这个参数,这里我们先设置为FALSE);返回值:WSA_WAIT_TIMEOUT :最常见的返回值,我们需要做的就是继续WaitWSA_WAIT_FAILED : 出现了错误,请检查cEvents和lphEvents两个参数是否有效如果事件数组中有某一个事件被传信了,函数会返回这个事件的索引值,但是这个索引值需要减去预定义值 WSA_WAIT_EVENT_0才是这个事件在事件数组中的位置。具体的例子就先不在这里举了,后面还会讲到注意:WSAWaitForMultipleEvents函数只能支持由WSA_MAXIMUM_WAIT_EVENTS对象定义的一个最大值,是 64,就是说WSAWaitForMultipleEvents只能等待64个事件,如果想同时等待多于64个事件,就要 创建额外的工作者线程,就不得不去管理一个线程池,这一点就不如下一篇要讲到的完成例程模型了。 4. WSAGetOverlappedResult 函数 既然我们可以通过WSAWaitForMultipleEvents函数来得到重叠操作完成的通知,那么我们自然也需要一个函数来查询一下重叠操作的结果,定义如下BOOL WSAGetOverlappedResult (SOCKET s, // SOCKET,不用说了LPWSAOVERLAPPED lpOverlapped, // 这里是我们想要查询结果的那个重叠结构的指针LPDWORD lpcbTransfer, // 本次重叠操作的实际接收(或发送)的字节数BOOL fWait, // 设置为TRUE,除非重叠操作完成,否则函数不会返回// 设置FALSE,而且操作仍处于挂起状态,那么函数就会返回FALSE// 错误为WSA_IO_INCOMPLETE// 不过因为我们是等待事件传信来通知我们操作完成,所以我们这里设// 置成什么都没有作用…..-_-b 别仍鸡蛋啊,我也想说得清楚一些…LPDWORD lpdwFlags // 指向DWORD的指针,负责接收结果标志);这个函数没什么难的,这里我们也不需要去关注它的返回值,直接把参数填好调用就可以了,这里就先不举例了唯一需要注意一下的就是如果WSAGetOverlappedResult完成以后,第三个参数返回是 0 ,则说明通信对方已经关闭连接,我们这边的SOCKET, Event之类的也就可以关闭了。项目中待解决问题 项目的时间越来越近了,听到公司的意向订单也越来越多,压力袭来,必须尽快了,还有一些待解决问题:
总的就是这么多了,想到就继续补充吧! 04/07/2009 WINCE应用的UI实现方案 —— 上篇:几种UI实现方案比较一、MFC的硬伤 二、GDI的痛苦 三、GWES的探路,我不是先锋 四、最后的攻关,GWES API能否成为我们需要的坚实地基 嵌入式UI架构设计 //========================================================================TITLE: 嵌入式UI架构设计漫谈AUTHOR: norainsDATE: Friday 31-October-2008Environment: NONE//======================================================================== 和桌面清一色的采用explorer不同,嵌入式设备更多的采用是自定义的简单UI,即使是含有explorer的wince也是如此。因为对于嵌入式设备而言,功能强大并不是主打,简单易用才是根本。以目前国内的手持车载设备为例,大部分的公司卖的都是硬件,利润很大一部分取决于硬件成本的多寡。并且,每个系列的产品都会有不同的外围器件,而这也决定了无法所有的产品都用同一个UI程序。 class CImageTabBase 绘制图片时可以简单如此: 使用类的方式还有一个好处,就是如果遇到图片架构变更,只要添加新的ImageTab类即可,甚至可以通过配置文件来确定当前运行的程序应该选用何种界面: namespace StrTab 采用类封装方式,之前通过switch语句更新资源的代码可以更改如下: BOOL CMainCtrl::Initialize(HINSTANCE hInstance) 万变不离其宗,对于windows程序而言,最主要的还是窗口。很多时候,大家常用的做法是一个界面,就写一个源代码文件。这样当然简单,但带来的问题就是代码重复度高,没增加一个窗口就要增加一个文件,显得很累赘。所以,关于窗口,我们是采用只用一个窗口类,通过设置不同的数值,来生成形式各异的界面。 18/04/2009 整晚的失眠失眠...对于我来说挺遥远的,特别是因为情感问题!但是,昨天我失眠了,失得很彻底,很窝囊!我努力的寻找着我该处在的位置,我找不到...为什么我苦苦寻求的简单的生活方式却又要有这样的事情发生呢?到底是谁在耍我? 07/04/2009 本命年伊始:心烦意乱一年的时间很快过去,本命年到来了,强迫我的妹妹买了根红绳给我挂着...我妹妹问:哥,你还信这个啊?我心里默默的说:我索要的是祝福,不是迷信。所以我回家了。这一年的时间里,我越来越感觉到亲情的重要了,我工作和生活的绝大部分动力都来自于我的家庭。朋友见面的时间越来越少了,言语之间,话题在变,但还是很开心。 今年年过得很开心,参加了同学的婚礼,见到了所有我想见的人。大家都有所改变,但是聊天时还不乏校园的一种稚气,只是越来越模糊了!不知道为什么,这些年来,想到同学的时候心里总是有一些伤感,总是再回忆过去。大家的生活渐行渐远,也不止大家是否一如既往的开心。 就先写一点吧,其实也不知道该写些什么,也许是我自己太感伤了! 离忆想起那些日子,不能回忆的是高考后的心理压力,同时还有的就是离别的痛苦,也让我不能自拔了好长一段的时间。但是,有段回忆却是彩色的,暂且叫它离忆吧。 25/05/2008 辞职关于辞职,我已经想过很久了。从3月底部门架构重组后到现在,思考的时间也差不多历时一个月了。前天从公司的一大堆通告、表格中找到了《员工辞职申请表》,下定决心离职! 这是我的第一份工作,在即将离别之际,我不由的想起初由学校来深圳那些日子。毕业之处的茫然挂在每个人的脸上,当时的我们不断的宣泄着离别带来的痛苦,亦或是自我麻痹——我们每天都去学校后门的网吧,玩着游戏、吃便宜炒饭、聊通宵的天。这是我们选择的对将逝去的校园生活的一种祭奠。这不是堕落,也不是发泄,是抵抗,是依赖。这是在表达感情,没有人能要求什么,改变什么。最后的这段时光,随着分别的日子,随风飘走。走的那天,我清晰记得的眼泪也散落在了视野之外。这是我的追忆! 依稀记得在学校门口和涛的一段对话。 涛:毕业了有什么打算? 我:不知道,想还是想做网络方面的吧。你呢? 涛:我还是在南昌这边,先做段时间,看看朋友们那边怎么样。 我:朋友那边,做什么? 涛:我们家那边很多做铝合金生意的,他们比我早出来,现在已经很不错了,可能会先跟着他们混。 我:哦,我还是那个想法,想做3G方面的东西,找个这方面的工作吧。 涛:恩,你还是可以的,努力去做啊! 我:恩,一起加油。 这其中其实已经是最简陋的一个“职业规划”了,我们都有各自的想法。不知道涛哥现在还记不记得,我一直都记得。这样的交流在同学们之间都很多,我知道,但很模糊。这想法随着我的旅程也到了深圳,在这城市的第四天便去书城买了《移动通信类职位应聘指南》这本书,虽然其中的内容大多跟我的专业相差比较远,但是我看到移动通信产业链中sp这一块,这是我为之兴奋的一点。随后,我开始跑人才市场、投简历、面试,然后循环这一过程,我逐渐适应,但是慢慢的忘却了想法。就业——是我那个时候的必要任务。当时的日子我想众众应该印象深刻,这里我不想说,以后再写吧! 我想天道酬勤是不会错的,一面、笔试、二面一路pass第一份工作就找到了,而且一干就是一年。这一年工作中的心态也经历了几种转变。重一开始的充满激情,到对工作出现不满,一直到现在发现我真的不适合做着份工作,我开始了新的思考。这段时间以来,我一直在回溯我的记忆,找寻着自我。在大学里,都在摸索着,但是现在怎么就不对劲呢?一句话无意中点醒了我——知之者不如好之者,好之者不如乐之者。我的兴趣不在这里,我的工作不应该是那些,辞职! 最近,阿甘这边沟通也很多,他的想法要稍多些,我毕竟不在这个行当里,想法自然少些。但是我们对我们的目标少了些激情,我不认为这是件坏事,至少我们现在都理智了很多。对待一些已有的想法也更趋于实际。但我还是担心的,因为他说过我们不能共事,说实话,我一直都猜不透这句话。这次我回南昌为的就是这个事情! 兄弟们,记得自己曾经想要的,去追求吧,厚积薄发! 04/05/2008 忍者神龟昨天我看了07年上映的美国动画片《忍者神龟》。其实,这部电影我早就想看了,只是当时上映的时间正好是我毕业的时间,没有时间去看。想看这部影片的初衷很简单,小时候我们经常玩这个游戏,所以有点怀旧的味道在里面。 这次看感觉还不错,也找到了我应有的回忆。惯使武士刀的“蓝霹雳”莱昂纳多、手持木棒的“爱因斯坦”多纳泰罗、暗藏忍者匕首的“火爆红”拉斐尔和双节棍舞得虎虎有声的“掉链子”米开朗琪罗,利落身手和聪明头脑比任何超级英雄都毫不逊色的小龟们,个个都是个性十足、忍者功夫精到的全能高手。 除此之外,我也还发现不少的东西。莱昂与拉斐尔之间的矛盾体现了真正的友谊、四兄弟的并肩作战体现了什么是团队精神、忍者的修炼之路体现了什么是奋斗。这些都是在现实中不那么清晰的东西。其中的人物性格刻画我也十分喜欢,莱昂的自负、多纳泰罗的责任心、米开朗琪罗真实的自我和拉斐尔的执着都是让我心生共鸣的地方。 如此性格迥异的四只乌龟却能为了一个共同的目标而团结再一起,进而去做自己想做的事情,这是让我感动的地方。鼠老大说:“你的兄弟都有优点和弱点,当他们处于弱势时你就应强大起来,如果你不能认识到这个,那么这个家没有希望..”,这句话让我感觉到什么是真正的兄弟。是的,我也有我的兄弟,我们也有着共同的理想,但是我们有点在生活中迷失了自我,正如影片开始的时候那样。记住自己心中所想的,如拉斐尔一样的执着,我想是会有再聚在一起的一天的!我们都在修炼,蓄势待发! 01/05/2008 间断性思维这个词是在上班的时候突然想到的,想到了就记下来了。其实我想这个词是最能表达我这段时间以来做事的一个方式了。 很多的时候,我的思维和我行为完全的脱离开来了。而思维一直都是断断续续的分散在行为中间,一段一段的......我想这个就是我对待生活比较疲软的原因吧!清晰的思路常常出现在起床去上班的时候、中午休息的时候和晚上躺在床上的时候,这个时候我才想着我最想要的是什么,我所追求的是什么。但是,一旦我进入到工作中,甚至是娱乐中,我会忘记那些我所想!我不知道我这是为什么,我想我是害怕了,害怕这些太遥远,不是我现在的生活所能够给予的,正如我害怕开始一样。想变...... 我想,我乱...... 不止一次的朋友和我谈起关于职业的方向选择的事,我想我是有一个坚定的立场的,我想。这些思路也在我的脑海里以间断性的思维不断的出现,我是相信我仍然相信的,我是要回到我的兴趣所在的。而我这段时间以来,很多羁绊,社会经验不丰富也好、职场经验不足也好、经济条件制约也好、自己害怕也好,我想我是习惯这些了。 恍惚的思念 天气莫名其妙的好,心情也跟着很好。太阳射进窗户的那一刹那,我还静静的躺在床上,很舒服,很温暖!躺在窗上静静的回忆的,思绪断断续续。冬天深圳的阳光难得有这样的柔和的,让我想起了在学校。工作就是这样,让人忘却的东西太多了,你的激情,你的精力,你所在乎的东西都在一点一点的消失,患得患失! 22/04/2007 在百度的日子里 时间过得真的挺快的`等我想起来这里写点什么的时候,我已经身在深圳了``也许决定来深圳的理由很简单-IT公司多达1650多家,俗话说瘦死的骆驼比马大,所以我就来了``但是我的决定是没有错的,深圳是一个移民城市,不象北京、上海存在“歧视”问题。而且深圳是经济特区,一个在高度发展中的城市,对我来说这是一个不错的选择。
刚下火车那会,并没有意料中的那种激动与兴奋,相反的是心情极度的平静。也许,是因为我没有怀着一个大的目标,一个远大的理想才来到这个城市的关系吧,我只想在这样一个拥挤的城市里找到一个属于我空间。我量力而行。
心情上的平静不能取代随之而来的焦虑与紧张,因为一切都是这样的陌生,这样的不可控制。我努力的去调整自己的心态,不断的给自己鼓励,希望自己能有一个好的开始。在众众的表姐家呆了两天后,我转住到了我叔叔家,那边离人才市场会更近一些,这样我不用每天的就这样的来回的跑了。准备好了行头之后(所谓的行头就衬衫、西裤和皮鞋 注:皮鞋被宰花了275心痛啊~~),便开始跑人才市场了。
初八一大早,我和众众带着上个世纪的简历冲到了人才大市场,脑袋一片空白。在这样一个拥挤不堪,人头篡动的空间里,我感觉到了竞争。
五元一张门票这样的现场招聘会天天都有,但是好象找工作的永远比提供的岗位多得多。 14/12/2006 今天算是忙了一天了,为了画一个系统结构图上网兜了一圈,想找一个专业的工具来描述一个系统。开始,我想到的是UML,可是OOD中没有系统结构图这个概念,而且UML中的视图(view)是对软件系统进行面对对象的描述和建模,而我是想通过系统分析建立一个系统的物理模型,类似系统的数据流图中的顶层图,通过这个图来对系统做个简要的描述。遍历了baidu之后,我发现了一个工具-Microsoft Office Visio 2007 -他是一款商用和科技图表制作程序,应用的范围很广,从家居规划到工程制图,从各种软件和数据库视图到商务的工作流程图甚至是营销图标,可以说是囊括所有的商业应用图表。下载...安装...打开来,没有我需要的系统结构图,但是研究了一会之后发现,它里面给出视图都是以模板的形式给出的,也就是说你可以创建自己需要的图表,嘿嘿,开工了```为了节省时间,我用了程序结构图做为模板进行绘制的。我所要描述的是一个搜索引擎系统,下面就是它的系统结构图了: 简要的说明一下,系统分为两个部分:
前端用来处理用户的查询请求,后台用来对用户的请求做出分析,然后在Index Files中查找到相应的数据对数据做出排序,再把结果返回给用户,整个图是按照数据流来绘制的。 通过这个图的绘制,个人感觉visio还是一个不错的软件,它能够很好的诠释你的想法,过程和系统,让你更好的完成整个系统的设计与分析。 10/12/2006 在台灯下度过的日子 嗯...扳手指头一算,这个星期来已经通宵了4,5天了,白天几乎都是在睡眠中度过的,晚上陪伴我的就只有我那盏小台灯了。在这样阴冷的天气里,有一个功率40w的取暖器还真的挺舒服的,而且我也很喜欢它泛出的那种柔和的黄光,让我有一种思念的感觉,孤独而又温暖。
最近一段时间都在"忙"着写论文,为什么要打双引号呢!这个我身边的人都知道,这个忙是要打折扣的。譬如,有人问你:嗨!最近在忙什么呢? 这个时候在你的大脑里浮现的肯定是对你,或者是对你的生活起着促进作用的事情,而现在我唯一要做的也就是好好的把毕业论文给写完了。(至于什么好好学习,天天向上之类的都是些后话了,在很长一段时间内我根本都不想提及这些)。
提及论文还真有些话是要说的。先说说给我们安排论文分组的计算机系秘书吧。丫就是一噱头,论文按你的姓氏来分组,根本不顾及你的专业方向和本人的意向,很不幸的我(网络模块)被分到了一个研究软件的小组里了,课题也和我的网络一点关系也没有,完全就是软件领域的课题。当我很气愤地跑到系办公室抗议:这不公平!教学秘书一句话:“你觉得这个社会什么对你来说才是公平的呢?”顿时,我无言以对。 基于JDK1.5.0+tomcat5.0+Eclipse3.2.1的web应用程序开发平台的搭建 最近由于论文的需要,所以要搭建一个web应用程序的开发环境,程序采用java进行开发,所以下面对整个应用程序的开发环境的配置做个介绍:
1. JDK1.5(Java Development Kit)
这是SUN公司的一个开发工具集,它为java提供了一个丰富的语言和运行环境,开发人员和最终用户都可以利用这个工具来开发java程序。
下载完成后开始安装JDK1.5,下载下来的是一个安装文件,双击它就可以安装,安装过程比较简单基本上一路next就可以了,不过要注意下你的安装目录还有你所使用的浏览器。之后会要求你重起系统,这里建议先不要同意,等JDK的环境变量配置完成后再重新启动计算机。
JDK配置:
1. 用鼠标右键单击桌面上的我的电脑,在弹出的快捷菜单中选择“属性”选项。(这里我就不贴图了,麻烦 -_-! 我尽量写详细些吧)
2. 在弹出的“系统属性”中选择“高级”选项卡中的“环境变量”按钮,弹出“环境变量”对话框。
3. 单击“系统变量”区域中的新建按钮,在弹出的“新建系统变量”对话框中,添加如下环境变量 (假定JDK安装在D:\java\jdk1.5.0)
变量名: CLASSPATH
变量值: D:\Java\jdk1.5.0\;D:\Java\jdk1.5.0\lib\tools.jar;D:\Java\jdk1.5.0\lib\dt.jar;D:\Java\jdk1.5.0\bin
4. 选中“系统变量”区域中的Path变量,在弹出的“编辑系统变量”对话框中为path变量,追加如下变量值:
变量名: PATH
变量值: D:\Java\jdk1.5.0\bin\
配置完成后,重新启动计算机,ok~ JDK配置完毕。
2. Tomcat5.0
Tomcat是Apache Group Jakarta 小组开发的支持JSP和Servlet的免费服务器软件。
tomcat的安装比较简单,一路next就ok了,需要注意的是tomcat服务的启动需要jdk,因为tomcat本身就是用java编写的程序,所以程序的运行就需要java解释器。
tomcat配置:
1. 安装Tomcat后,在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量(假定你的tomcat安装在c:\tomcat):
CATALINA_HOME=c:\tomcat CATALINA_BASE=c:\tomcat 2. 然后修改环境变量中的classpath,把tomat安装目录下的common\lib下的(可以根据实际追加)servlet.jar追加到classpath中去,修改后的classpath如下 (%JAVA_HOME%指的是JDK的安装目录): classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\common\lib\servlet.jar; 3. 接着可以启动tomcat,在IE中访问http://localhost:8080,如果看到tomcat的欢迎页面的话说明安装成功了。 3. Eclipse
Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括 Java 开发工具(Java Development Tools,JDT)。
下载下来的将是一个压缩包,解压之后就可以运行了,不需要安装。
从eclipse官方网站下载的只带有基本的几个插件,如果要多种J2EE的元素、Web应用的开发和最流行的应用服务器结合为一体就要向eclipse中添加插件,现在网上这样的插件有很多,这里我推荐使用lomboz(它是Eclipse的一个主要的开源插件(open-source plug-in),Lomboz插件能够使Java开发者更好的使用Eclipse去创建,调试和部署一个100%基于J2EE的Java应用服务器。)
至于如何向eclipse中添加lomboz这样的文章网上有很多,稍微baidu一下就可以找到答案了,我就不在这里敖述了。这里我要介绍一个IBM的Callisto Simultaneous Release project,这个是IBM的一个developerWorks,它提供了带有集成开发环境插件包的eclips它们分别是:
其中第一项就是关于web应用程序开发的,我们可以下载,地址是:http://www-128.ibm.com/developerworks/eclipse。这其中已经包括了web应用程序的开发环境了,不用进行任何多余的配置了,挺爽的,功能比Lomboz还要多些。 (o.O 呵呵,走了一条捷径~~) 这样一个基于JDK1.5.0+Tomcat5.0+Eclipse3.2.1的web应用程序开发平台基本上就搭建完毕了,呼呼~~~~ |
|
|